Spring boot

Vers le Haut 2022-01-15 02:47:13 阅读数:654

spring boot

SpringBoot2

Un..SpringBoot2Introduction

1.Exigences en matière d'études

Exigences en matière d'études
-FamiliarisationSpringBase
-FamiliarisationMavenUtiliser

Exigences environnementales
Java8Et plus
Maven 3.3Et plus

Matériel d'apprentissage
Spring BootSite officiel
Spring BootDocuments officiels

2.SpringEcosphère

SpringQue peut - on faire?? SpringCapacité de?Site officielhttp://spring.io

SpringL'écologie de:

webDéveloppement
Accès aux données
Contrôles de sécurité
Distribué
Service de messagerie
Développement mobile
Traitement par lots

Spring5Améliorations majeures:

Programmation réactive

[Impossible de transférer l'image de la chaîne externe,Il peut y avoir un mécanisme antivol à la station source,Il est recommandé de sauvegarder l'image et de la télécharger directement(img-xrWLEqEK-1641479793635)(image/7.jpg)]

Conception du code source interne
Basé surJava8Quelques nouvelles caractéristiques de,Par exemple::Implémentation par défaut de l'interface.Redessiner l'architecture du code source.

3.SpringBootAvantages

Pourquoi?SpringBoot?
Spring Boot makes it easy to create stand-alone, production-grade Spring based Applications that you can “just run”Créer rapidement des niveaux de productionSpringApplication.

SpringBootAvantages:
Create stand-alone Spring applications

Créer une indépendanceSpringApplication
Embed Tomcat, Jetty or Undertow directly (no need to deploy WAR files)

EmbeddedwebServeur
Provide opinionated ‘starter’ dependencies to simplify your build configuration

AutomatiquestarterDépendance,Simplifier la configuration de construction
Automatically configure Spring and 3rd party libraries whenever possible

Configuration automatiqueSpringEt les fonctions de tiers
Provide production-ready features such as metrics, health checks, and externalized configuration

Surveillance au niveau de la production、Configuration du bilan de santé et de l'externalisation
Absolutely no code generation and no requirement for XML configuration

Pas de génération de code、Pas besoin d'écrireXML
SpringBootC'est l'intégration.SpringUn guichet unique pour la pile technologique

SpringBootC'est la simplification.SpringL'échafaudage de développement rapide de la pile technologique

SpringBootInconvénients:

La version personnelle de l'empereur,Itération rapide,La nécessité de rester attentif au changement
Le paquet est trop profond,Les principes internes sont complexes,Pas facile à maîtriser

4.SpringBootLe contexte historique de

Microservices

In short, the microservice architectural style is an approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms, often an HTTP resource API. These services are built around business capabilities and independently deployable by fully automated deployment machinery. There is a bare minimum of centralized management of these services, which may be written in different programming languages and use different data storage technologies.——James Lewis and Martin Fowler (2014)

Le micro - service est un style architectural,Une application est divisée en un ensemble de petits services,Chaque service fonctionne dans son propre processus,C'est - à - dire qu'il peut être déployé et mis à niveau indépendamment.Utilisation légère entre les servicesHTTPInteraction, La séparation des services autour des fonctions opérationnelles peut être déployée indépendamment par un mécanisme de déploiement entièrement automatisé .Décentralisation,Autonomie des services.Les services peuvent être offerts dans différentes langues、Différentes technologies de stockage.

Distribué

Difficultés de distribution:
Appel à distance
Découverte de services
Équilibrage de la charge
Tolérance aux pannes de service
Gestion de la configuration
Surveillance du service
Suivi des liens
Gestion des journaux
Calendrier des tâches

Solution distribuée:
SpringBoot + SpringCloud

[Impossible de transférer l'image de la chaîne externe,Il peut y avoir un mécanisme antivol à la station source,Il est recommandé de sauvegarder l'image et de la télécharger directement(img-FdPZhkl0-1641479793637)(image/6.jpg)]

Cloud Native

Comment les applications natives vont dans le cloud.

Difficultés à monter dans les nuages
Auto - guérison des services
Elastoscopie
Ségrégation des services
Déploiement automatisé
Publication en niveaux de gris
Gestion des flux

[Impossible de transférer l'image de la chaîne externe,Il peut y avoir un mécanisme antivol à la station source,Il est recommandé de sauvegarder l'image et de la télécharger directement(img-aO5seoa4-1641479793638)(image/5.jpg)]

5.SpringBootArchitecture officielle des documents

Spring BootSite officielhttps://spring.io/projects/spring-boot
Spring BootDocuments officielshttps://docs.spring.io/spring-boot/docs/

[Impossible de transférer l'image de la chaîne externe,Il peut y avoir un mécanisme antivol à la station source,Il est recommandé de sauvegarder l'image et de la télécharger directement(img-9CEetPe0-1641479793639)(image/1.jpg)]

[Impossible de transférer l'image de la chaîne externe,Il peut y avoir un mécanisme antivol à la station source,Il est recommandé de sauvegarder l'image et de la télécharger directement(img-NW15bQy0-1641479793640)(image/2.jpg)]

Voir les nouvelles propriétés de la versionhttps://github.com/spring-projects/spring-boot/wiki#release-notes

[Impossible de transférer l'image de la chaîne externe,Il peut y avoir un mécanisme antivol à la station source,Il est recommandé de sauvegarder l'image et de la télécharger directement(img-RIyB29VV-1641479793641)(image/3.jpg)]

2..SpringBootPremière connaissance

1.SpringBoot-HelloWorld

1.1 MavenConfiguration

MavenProfilsettings.xmlDocumentation

<localRepository>E:/93/6.JavaWebProject/repo</localRepository>
<mirrors>
<mirror>
<id>nexus-aliyun</id>
<mirrorOf>central</mirrorOf>
<name>Nexus aliyun</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
</mirrors>
<profiles>
<profile>
<id>jdk-1.8</id>
<activation>
<activeByDefault>true</activeByDefault>
<jdk>1.8</jdk>
</activation>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
</properties>
</profile>
</profiles>

1.2 NouveauMavenIngénierie

Besoins:Parcourir envoyer/helloDemande,Réponse “Hello,Spring Boot 2”

Première étape:CréationmavenIngénierie

Modifierpom.xml,Introduire des dépendances

<!-- Projet parent: Numéro de version dépendant , Version Centre d'arbitrage -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.4</version>
</parent>
<dependencies>
<!-- IntroductionwebDémarreur -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>

Deuxième étape:Créer le programme principal

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/** * @SpringBootApplication Classe de configuration principale * 1. Reconnu comme étant actuellement un SpringBootProjets pour * 2. Par défaut, seuls les composants sous le même paquet et ses sous - paquets sont scannés * 3. Les trois notes suivantes ont été remplacées * @SpringBootConfiguration * @EnableAutoConfiguration * @ComponentScan * * 4.Par désignationscanBasePackagesScan Pack, Mettre en vigueur les composants de son paquet * @SpringBootApplication(scanBasePackages = "com.igeek.springboot") */
@SpringBootApplication
public class MainApplication {

public static void main(String[] args) {

/** * just run Fonctionnement direct * Premier paramètre: Lequel SpringBootApplication de(Classe de programme principale) * Deuxième paramètre:mainParamètre formel de la méthode */
//Ce qui revient, c'estIOCObjet conteneur
ConfigurableApplicationContext ac = SpringApplication.run(MainApplication.class, args);
//VoirIOC Composants à l'intérieur du conteneur ,Qu'est - ce queBeanDefinition
String[] definitionNames = ac.getBeanDefinitionNames();
for (String name : definitionNames) {

System.out.println(name);
}
}
}

Troisième étape:Préparation des opérations

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/** * @RestController * 1.Notes combinées, Remplacer les deux notes ci - dessous ,La classe actuelle estController Classe et configurée pour IOCDans le récipient * 2.En coursController Toutes les méthodes dans jsonRetour du format des données * * @Controller * @ResponseBody */
@RestController
public class HelloController {

@RequestMapping("/hello")
public String handle01(){

return "Hello, Spring Boot 2!";
}
}

Quatrième étape:Exécution&Tests

ExécutionMainApplicationCatégorie
Entrée du navigateurhttp://localhost:8888/hello,Affichage de la pageHello, Spring Boot 2!.

Étape 5:Configuration de la configuration

mavenIngénierieresourcesCréer dans le dossierapplication.propertiesDocumentation.

#Modifier le numéro de port par défaut
server.port=8888

Plus d'informations sur la configurationhttps://docs.spring.io/spring-boot/docs/2.3.7.RELEASE/reference/html/appendix-application-properties.html#common-application-properties-server

Étape 6:Déploiement groupé

Inpom.xmlAjouter

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

InIDEADeMaven Cliquez sur exécuter sur le plug - in clean 、package,Prends ça.helloworld Packaging project as jarSac,Emballéjar Le paquet est généré à helloworld Projet d'ingénierie targetDans le dossier.

AveccmdExécutionjava -jar testSpringBoot-ch02-first-1.0-SNAPSHOT.jar, Peut fonctionner helloworldProjets d'ingénierie.

Oui.jar Le paquet peut être exécuté directement sur le serveur cible .

DécompresserjarSac, Vous pouvez trouver beaucoup de jarSac,Par exemple, intégrétomcat:

[Impossible de transférer l'image de la chaîne externe,Il peut y avoir un mécanisme antivol à la station source,Il est recommandé de sauvegarder l'image et de la télécharger directement(img-HdYRUwai-1641479793642)(image/image-20210323172701360.png)]

2.SpringBootCaractéristiques

2.1 SpringBoot-Fonction de gestion des dépendances

Gestion de la dépendance

Le projet parent gère les dépendances:

<!-- Projet parent: Numéro de version dépendant , Version Centre d'arbitrage -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.4</version>
</parent>

L'élément parent de l'élément ci - dessus est le suivant :

<!-- Il indique les numéros de version des dépendances couramment utilisées dans presque tous les développements ,Version automatique du mécanisme d'arbitrage -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.4.4</version>
</parent>

Il indique les numéros de version des dépendances couramment utilisées dans presque tous les développements ,Version automatique du mécanisme d'arbitrage.

Initiateur de scène

​ Développer l'importationstarterInitiateur de scène,J'en ai vu beaucoup. spring-boot-starter-* : * C'est une sorte de scène. starter,Nous introduisons automatiquement toutes les dépendances normalement requises pour ce scénario.PlusSpringBoot Tous les scénarios pris en charge vus *-spring-boot-starter: Les initiateurs de scénarios simplifiés développés par des tiers pour nous.

IntroductionwebDémarreur:

<!-- IntroductionwebDémarreur -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

Toutes les dépendances de bas niveau de l'initiateur de scène:

<!-- Toutes les dépendances de bas niveau de l'initiateur de scène -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.4.4</version>
<scope>compile</scope>
</dependency>

Arbitrage automatique des versions

​ Pas besoin de se concentrer sur le numéro de version,Arbitrage automatique des versions.L'introduction de dépendances par défaut ne peut pas écrire de version;Introduction of non - version Arbitrationjar,Pour écrire le numéro de version, Vous pouvez également modifier le numéro de version par défaut .

Voirspring-boot-dependencies Il spécifie la version actuellement dépendante pour key.
Outrepasser la configuration dans le projet actuel,Comme le code ci - dessous.

<!-- PersonnalisationMySqlNuméro de version de la Déclaration -->
<properties>
<mysql.version>5.1.38</mysql.version>
</properties>
<!-- IntroductionmysqlDépendance -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<!-- Introduire le numéro de version personnalisé spécifié -->
<version>${mysql.version}</version>
</dependency>

IDEARaccourcis clavier:

ctrl + shift + alt + U: Montrer graphiquement les relations entre les dépendances dans un projet .
alt + ins:équivalent àEclipseDe Ctrl + N,Créer une nouvelle classe, Nouveaux sacs, etc .

2.2 SpringBoot-Propriétés de configuration automatique

Auto fitTomcat

IntroductionTomcatDépendance.
ConfigurationTomcat

<!-- IntroductionTomcatDépendance,ConfigurationTomcat -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>2.4.4</version>
<scope>compile</scope>
</dependency>

Auto fitSpringMVC

IntroductionSpringMVCEnsemble complet de composants.
Auto fitSpringMVCComposants communs(Fonction),Auto fitWebFonctions communes,Par exemple:: Problèmes d'encodage des caractères, etc. .

SpringBootPour nous aider à configurer toutwebScénarios communs développés

/** * @SpringBootApplication Classe de configuration principale * 1. Reconnu comme étant actuellement un SpringBootProjets pour * 2. Par défaut, seuls les composants sous le même paquet et ses sous - paquets sont scannés * 3. Les trois notes suivantes ont été remplacées * @SpringBootConfiguration * @EnableAutoConfiguration * @ComponentScan * * 4.Par désignationscanBasePackagesScan Pack, Mettre en vigueur les composants de son paquet * @SpringBootApplication(scanBasePackages = "com.igeek.springboot") */
@SpringBootApplication
public class MainApplication {

public static void main(String[] args) {

/** * just run Fonctionnement direct * Premier paramètre: Lequel SpringBootApplication de(Classe de programme principale) * Deuxième paramètre:mainParamètre formel de la méthode */
//1.Ce qui revient, c'estIOCObjet conteneur
ConfigurableApplicationContext ac = SpringApplication.run(MainApplication.class, args);
//2.VoirIOC Composants à l'intérieur du conteneur ,Qu'est - ce queBeanDefinition
String[] definitionNames = ac.getBeanDefinitionNames();
for (String name : definitionNames) {

System.out.println(name);
}
}
}

Structure par défaut du paquet

.Les composants du paquet dans lequel se trouve le programme principal et tous ses sous - paquets sont scannés par défaut,Aucune configuration de numérisation de paquets précédente n'est nécessaire.

Pour changer le chemin de scan

@SpringBootApplication(scanBasePackages="com.igeek.springboot")
équivalent à
@ComponentScan("com.igeek.springboot")
@SpringBootApplication
équivalent à
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.igeek.springboot")

Différentes configurations ont des valeurs par défaut

​ La configuration par défaut est finalement mappée à une classe,Par exemple::MultipartProperties. Les valeurs du profil sont finalement liées à chaque XxxPropertiesEn classe,Cette classe crée des objets dans le conteneur,Charger tous les éléments de configuration automatique à la demande.

Beaucoup.starter

Quels scénarios ont été introduits la configuration automatique de ce scénario sera activée
SpringBootToutes les fonctions de configuration automatique sontspring-boot-autoconfigureÀ l'intérieur.

3.SpringBootNotes de bas niveau

3.1 Notes de bas [email protected]étails

1.Configurer la classe

package com.igeek.springboot.config;
import com.igeek.springboot.entity.Car;
import com.igeek.springboot.entity.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/** * @Configuration * 1. Classes de configuration personnalisées ,équivalent àxmlProfil,La classe de configuration elle - même est un composant * 2.Utilisé dans la classe de [email protected] la méthode d'enregistrement des composants du conteneur,La valeur par défaut est également une seule instance * * 3.PropriétésproxyBeanMethods * 3.1 FullMode:Par défauttrue * > Utilisé pour surveiller les IOC Y a - t - il cette instance dans le conteneur? , S'il y en a un, il ne sera plus créé , Retour direct à cette seule instance ; * > Informations d'instance pour la classe de configuration actuelle :com.ige[email protected]aa21042 Objet Proxy * 3.2 LiteMode:Désigné commefalse * > Chaque appel crée une nouvelle instance ; * > Informations d'instance pour la classe de configuration actuelle :[email protected] * * Utilisez le résumé du scénario: * LiteMode,DésignationproxyBeanMethodsLa valeur est:false, Pour configurer l'absence de dépendance entre les composants de la classe LiteLe mode accélère le processus de démarrage du conteneur, Réduire la configuration du jugement * FullMode,Désignation par défautproxyBeanMethodsLa valeur est:true, Il y a des dépendances entre les composants de la classe ,La méthode est appelée pour obtenir le composant instance unique précédent */
@Configuration(proxyBeanMethods = false)
public class MyConfig1 {

/** * @Bean Notes * 1. Renvoie la valeur de la méthode courante ,Ajouter àIOCDans le récipient; * 2.Le nom de la méthode est utilisé par défaut commebeanName * @return */
@Bean("p1")
public Person p(){

Person p = new Person("Li - si."," Huaibei, Anhui ");
//MontageCar
p.setCar(car());
return p;
}
@Bean
public Car car(){

return new Car("Big Ben",500000.0);
}
}

2.Catégorie d'essai

@ConfigurationLes codes d'essai sont les suivants::

/** * @SpringBootApplication Classe de configuration principale * 1. Reconnu comme étant actuellement un SpringBootProjets pour * 2. Par défaut, seuls les composants sous le même paquet et ses sous - paquets sont scannés * 3. Les trois notes suivantes ont été remplacées * @SpringBootConfiguration * @EnableAutoConfiguration * @ComponentScan * * 4.Par désignationscanBasePackagesScan Pack, Mettre en vigueur les composants de son paquet * @SpringBootApplication(scanBasePackages = "com.igeek.springboot") */
@SpringBootApplication
public class MainApplication {

public static void main(String[] args) {

/** * just run Fonctionnement direct * Premier paramètre: Lequel SpringBootApplication de(Classe de programme principale) * Deuxième paramètre:mainParamètre formel de la méthode */
//1.Ce qui revient, c'estIOCObjet conteneur
ConfigurableApplicationContext ac = SpringApplication.run(MainApplication.class, args);
//2.Voir le courantIOCDans le récipient,Qu'est - ce quebeanExemple
Person p = ac.getBean("p1", Person.class);
System.out.println("person:"+p);
Car car1 = ac.getBean("car", Car.class);
System.out.println("car1:"+car1);
//3.Obtenir la classe de configuration
MyConfig1 myConfig1 = ac.getBean(MyConfig1.class);
System.out.println("MyConfig1:"+myConfig1);
}
}

3.Utiliser le scénario

Pour configurer l'absence de dépendance entre les composants de la classe LiteLe mode accélère le processus de démarrage du conteneur, Réduire la configuration du jugement

Il y a des dépendances entre les composants de la classe ,La méthode est appelée pour obtenir le composant instance unique précédent,AvecFullMode(Par défaut)

IDEARaccourcis clavier:
Alt + Ins:Générergetter,setter、 Codes tels que constructeur .

Ctrl + Alt + B: Voir le Code d'implémentation spécifique de la classe .

3.2 Notes de bas [email protected] des composants

1.Notes communes

[email protected]、@Component、@Controller、@Service、@Repository,Ils sontSpringÉtiquette de base pour,InSpring Boot Ils n'ont pas changé leur fonction originale .

[email protected] Ajouter un paquet de numérisation de conteneur spécifié

[email protected]({User.class})Créer automatiquement ces deux types de composants dans le conteneur、Le nom du composant par défaut est le nom complet de la classe

[email protected]

package com.igeek.springboot.config;
import com.igeek.springboot.entity.Person;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportResource;
/** * @Configuration * 1. Classes de configuration personnalisées ,équivalent àxmlProfil * 2.DeSpringDeIOC Obtenir une instance dans le conteneur ,La valeur par défaut est Singleton * * Enregistrer l'Instance à IOCDans le récipient: * 1.La première façon:Utilisation de la mé[email protected], Enregistrer la valeur de retour de la méthode à IOCDans le récipient,Le nom de la méthode est utilisé par défaut commebeanName, Mais vous pouvez également spécifier ,Par exemple:p1 * 2.La deuxième façon: En configurant la classe @ConfigurationMoyenne,[email protected]({Person.class}), Enregistrer l'Instance à IOCDans le récipient, Par défaut, le nom de classe complet de l'Instance est utilisé comme beanName,Par exemple:com.igeek.springboot.entity.Person * 3.La troisième façon: En configurant la classe @ConfigurationMoyenne,[email protected]({"classpath:beans.xml"}),Oui.xmlImportation de profils, Pour configurer beanEntrée en vigueur,Par exemplebeans.xmlConfiguré danspersonDebeanExemple */
@Import({
Person.class})
@ImportResource({
"classpath:beans.xml"})
@Configuration
public class MyConfig2 {

}

3.Catégorie d'essai

package com.igeek.springboot;
import com.igeek.springboot.config.MyConfig1;
import com.igeek.springboot.config.MyConfig3;
import com.igeek.springboot.entity.Address;
import com.igeek.springboot.entity.Car;
import com.igeek.springboot.entity.Person;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
/** * @SpringBootApplication Classe de configuration principale * 1. Reconnu comme étant actuellement un SpringBootProjets pour * 2. Par défaut, seuls les composants sous le même paquet et ses sous - paquets sont scannés * 3. Les trois notes suivantes ont été remplacées * @SpringBootConfiguration * @EnableAutoConfiguration * @ComponentScan * * 4.Par désignationscanBasePackagesScan Pack, Mettre en vigueur les composants de son paquet * @SpringBootApplication(scanBasePackages = "com.igeek.springboot") */
@SpringBootApplication
public class MainApplication {

public static void main(String[] args) {

/** * just run Fonctionnement direct * Premier paramètre: Lequel SpringBootApplication de(Classe de programme principale) * Deuxième paramètre:mainParamètre formel de la méthode */
//1.Ce qui revient, c'estIOCObjet conteneur
ConfigurableApplicationContext ac = SpringApplication.run(MainApplication.class, args);
//2.Obtenir le courantIOCTous lesbeanExemple
String[] beanNames = ac.getBeanNamesForType(Person.class);
for (String beanName : beanNames) {

System.out.println(beanName);
}
}
}

3.3 Notes de bas [email protected] conditionnel

Montage conditionnel:SatisfactionConditionalConditions spécifiées,Injecter les composants

1.Configurer la classe

[email protected]

package com.igeek.springboot.config;
import com.igeek.springboot.entity.Address;
import com.igeek.springboot.entity.Car;
import com.igeek.springboot.entity.Person;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportResource;
/** * @Configuration * 1. Classes de configuration personnalisées ,équivalent àxmlProfil * 2.DeSpringDeIOC Obtenir une instance dans le conteneur ,La valeur par défaut est Singleton * * @Conditional Montage conditionnel * @ConditionalOnMissingBean Une foisIOCNon spécifié dans le conteneurbeanExemple,Alors lebeanAjouter àIOCDans le récipient * @ConditionalOnBean Une foisIOCSpécifié dans le conteneurbeanExemple,Alors lebeanAjouter àIOCDans le récipient */
@Configuration
//@ConditionalOnMissingBean(value = Car.class)
@ConditionalOnBean(value = Car.class)
public class MyConfig3 {

//Une foisIOCIl n'y a pas dec2DebeanExemple, Et il sera assemblé avec p2
//@ConditionalOnMissingBean(value = Car.class)
@Bean("p2")
public Person p(){

return new Person("Li - si."," Huaibei, Anhui ");
}
@Bean("c2")
public Car car(){

return new Car("Big Ben",500000.0);
}
}

2.Catégorie d'essai

package com.igeek.springboot;
import com.igeek.springboot.config.MyConfig1;
import com.igeek.springboot.config.MyConfig3;
import com.igeek.springboot.entity.Address;
import com.igeek.springboot.entity.Car;
import com.igeek.springboot.entity.Person;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
/** * @SpringBootApplication Classe de configuration principale * 1. Reconnu comme étant actuellement un SpringBootProjets pour * 2. Par défaut, seuls les composants sous le même paquet et ses sous - paquets sont scannés * 3. Les trois notes suivantes ont été remplacées * @SpringBootConfiguration * @EnableAutoConfiguration * @ComponentScan * * 4.Par désignationscanBasePackagesScan Pack, Mettre en vigueur les composants de son paquet * @SpringBootApplication(scanBasePackages = "com.igeek.springboot") */
@SpringBootApplication
public class MainApplication {

public static void main(String[] args) {

/** * just run Fonctionnement direct * Premier paramètre: Lequel SpringBootApplication de(Classe de programme principale) * Deuxième paramètre:mainParamètre formel de la méthode */
//1.Ce qui revient, c'estIOCObjet conteneur
ConfigurableApplicationContext ac = SpringApplication.run(MainApplication.class, args);
//2.Obtenir le courantIOCTous lesbeanExemple
String[] beanNames = ac.getBeanNamesForType(Person.class);
for (String beanName : beanNames) {

System.out.println(beanName);
}
//3.Obtenir la classe de configuration NoSuchBeanDefinitionException
MyConfig3 myConfig3 = ac.getBean(MyConfig3.class);
System.out.println("MyConfig3:"+myConfig3);
}
}

3.4 Notes de bas [email protected]

Supposons que le projet original soit toujours SSMDe,Peut mettre tous lesxmlProfil,[email protected] Importer pour utilisation

1.beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="person" class="com.igeek.springboot.entity.Person" p:username="Zhang San" p:address="Jiangsu Wuxi" p:car-ref="car"></bean>
<bean id="car123" class="com.igeek.springboot.entity.Car" p:label="Audi" p:price="300000.0"></bean>
</beans>

2.Configurer la classe

package com.igeek.springboot.config;
import com.igeek.springboot.entity.Person;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportResource;
/** * @Configuration * 1. Classes de configuration personnalisées ,équivalent àxmlProfil * 2.DeSpringDeIOC Obtenir une instance dans le conteneur ,La valeur par défaut est Singleton * * Enregistrer l'Instance à IOCDans le récipient: * 1.La première façon:Utilisation de la mé[email protected], Enregistrer la valeur de retour de la méthode à IOCDans le récipient,Le nom de la méthode est utilisé par défaut commebeanName, Mais vous pouvez également spécifier ,Par exemple:p1 * 2.La deuxième façon: En configurant la classe @ConfigurationMoyenne,[email protected]({Person.class}), * Enregistrer l'Instance à IOCDans le récipient, Par défaut, le nom de classe complet de l'Instance est utilisé comme beanName,Par exemple:com.igeek.springboot.entity.Person * 3.La troisième façon: En configurant la classe @ConfigurationMoyenne,[email protected]({"classpath:beans.xml"}), * Oui.xmlImportation de profils, Pour configurer beanEntrée en vigueur,Par exemplebeans.xmlConfiguré danspersonDebeanExemple */
@Import({
Person.class})
@ImportResource({
"classpath:beans.xml"})
@Configuration
public class MyConfig2 {

}

3.Catégorie d'essai

public static void main(String[] args) {

//1、Retour à nousIOCConteneur
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
//2、 Le test contient - il un bean
boolean person = run.containsBean("person");
boolean car123 = run.containsBean("car123");
System.out.println("person:"+person);//true
System.out.println("car123:"+car123);//true
}

3.5 Notes de bas [email protected] la liaison

Comment utiliserJavaLire àpropertiesContenu du fichier,Et l'encapsule dansJavaBeanMoyenne,Pour une utilisation immédiate

1.Méthodes traditionnelles

public class getProperties {

public static void main(String[] args) throws FileNotFoundException, IOException {

Properties pps = new Properties();
pps.load(new FileInputStream("a.properties"));
Enumeration enum1 = pps.propertyNames();//Obtenir le nom du profil
while(enum1.hasMoreElements()) {

String strKey = (String) enum1.nextElement();
String strValue = pps.getProperty(strKey);
System.out.println(strKey + "=" + strValue);
//Encapsulé dansJavaBean.
}
}
}

2.Spring Boot Une liaison de configuration de configuration

@ConfigurationProperties + @Component

2.1 Supposons qu'il y ait un profil application.properties
myaddr.city=Jiangsu Wuxi
myaddr.street=New Wu District
2.2 pom.xmlMoyenne
<!-- IntroductionlombokDépendance -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>

InFile -> Settings ->Plugins -> InstallationlombokPlug - in

2.3 Configurer la liaison
package com.igeek.springboot.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/** * Configurer la liaison: * [email protected](prefix = "myaddr") * 2.Capable depropertiesSur le document, Utiliser le préfixe spécifié pour manipuler les propriétés de la classe * 3. Doit être utilisé avec ,Uniquement les composants dans le conteneur,Pour avoirSpringBootPuissance fournie * Première combinaison : * 1)[email protected] + @ConfigurationProperties(prefix = "myaddr") * 2). Dans ce cas, bean Pour compléter la configuration d'annotation ci - dessus * Le deuxième type est utilisé en combinaison : * 1)[email protected](Address.class) + @ConfigurationProperties(prefix = "myaddr") * 2)[email protected] Terminé dans la classe de configuration */
@Component
@ConfigurationProperties(prefix = "myaddr")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Address {

private String city;
private String street;
}
2.4 Catégorie d'essai
package com.igeek.springboot;
import com.igeek.springboot.config.MyConfig1;
import com.igeek.springboot.config.MyConfig3;
import com.igeek.springboot.entity.Address;
import com.igeek.springboot.entity.Car;
import com.igeek.springboot.entity.Person;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
/** * @SpringBootApplication Classe de configuration principale * 1. Reconnu comme étant actuellement un SpringBootProjets pour * 2. Par défaut, seuls les composants sous le même paquet et ses sous - paquets sont scannés * 3. Les trois notes suivantes ont été remplacées * @SpringBootConfiguration * @EnableAutoConfiguration * @ComponentScan * * 4.Par désignationscanBasePackagesScan Pack, Mettre en vigueur les composants de son paquet * @SpringBootApplication(scanBasePackages = "com.igeek.springboot") */
@SpringBootApplication
public class MainApplication {

public static void main(String[] args) {

/** * just run Fonctionnement direct * Premier paramètre: Lequel SpringBootApplication de(Classe de programme principale) * Deuxième paramètre:mainParamètre formel de la méthode */
//Ce qui revient, c'estIOCObjet conteneur
ConfigurableApplicationContext ac = SpringApplication.run(MainApplication.class, args);
//AccèsAddressExemple
Address address = ac.getBean(Address.class);
//AccèsAddressDebeanExemple
System.out.println(address.getCity());
System.out.println(address.getStreet());
}
}

3.Spring Boot Une autre configuration configure la liaison

@EnableConfigurationProperties + @ConfigurationProperties

3.1 Supposons qu'il y ait un profil application.properties
myaddr.city=Jiangsu Wuxi
myaddr.street=New Wu District
3.2 Configurer la classe
package com.igeek.springboot.config;
import com.igeek.springboot.entity.Address;
import com.igeek.springboot.entity.Car;
import com.igeek.springboot.entity.Person;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportResource;
/** * @Configuration * 1. Classes de configuration personnalisées ,équivalent àxmlProfil * 2.DeSpringDeIOC Obtenir une instance dans le conteneur ,La valeur par défaut est Singleton */
@Configuration
//OuvertAddress Configurer la fonction de liaison AddressCe composant est automatiquement enregistré dans le conteneur 
@EnableConfigurationProperties(Address.class)
public class MyConfig3 {

}
3.3 Configurer la liaison
package com.igeek.springboot.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/** * Configurer la liaison: * [email protected](prefix = "myaddr") * 2.Capable depropertiesSur le document, Utiliser le préfixe spécifié pour manipuler les propriétés de la classe * 3. Doit être utilisé avec ,Uniquement les composants dans le conteneur,Pour avoirSpringBootPuissance fournie * Première combinaison : * 1)[email protected] + @ConfigurationProperties(prefix = "myaddr") * 2). Dans ce cas, bean Pour compléter la configuration d'annotation ci - dessus * Le deuxième type est utilisé en combinaison : * 1)[email protected](Address.class) + @ConfigurationProperties(prefix = "myaddr") * 2)[email protected] Terminé dans la classe de configuration */
//@Component
@ConfigurationProperties(prefix = "myaddr")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Address {

private String city;
private String street;
}
3.4 Catégorie d'essai
package com.igeek.springboot;
import com.igeek.springboot.config.MyConfig1;
import com.igeek.springboot.config.MyConfig3;
import com.igeek.springboot.entity.Address;
import com.igeek.springboot.entity.Car;
import com.igeek.springboot.entity.Person;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
/** * @SpringBootApplication Classe de configuration principale * 1. Reconnu comme étant actuellement un SpringBootProjets pour * 2. Par défaut, seuls les composants sous le même paquet et ses sous - paquets sont scannés * 3. Les trois notes suivantes ont été remplacées * @SpringBootConfiguration * @EnableAutoConfiguration * @ComponentScan * * 4.Par désignationscanBasePackagesScan Pack, Mettre en vigueur les composants de son paquet * @SpringBootApplication(scanBasePackages = "com.igeek.springboot") */
@SpringBootApplication
public class MainApplication {

public static void main(String[] args) {

/** * just run Fonctionnement direct * Premier paramètre: Lequel SpringBootApplication de(Classe de programme principale) * Deuxième paramètre:mainParamètre formel de la méthode */
//Ce qui revient, c'estIOCObjet conteneur
ConfigurableApplicationContext ac = SpringApplication.run(MainApplication.class, args);
//AccèsAddressExemple
Address address = ac.getBean(Address.class);
//AccèsAddressDebeanExemple
System.out.println(address.getCity());
System.out.println(address.getStreet());
}
}

4.Configuration automatique【Analyse des sources】

4.1 Configuration automatique【Analyse des sources】- Principe de la règle du paquet automatique

Spring Boot Classe de démarrage de l'application

@SpringBootApplication
public class MainApplication {

public static void main(String[] args) {

SpringApplication.run(MainApplication.class, args);
}
}

1)、[email protected]

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {
@Filter(
type = FilterType.CUSTOM,
classes = {
TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {
AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {

...
}

Attention!:Analyse de l'[email protected],@EnableAutoConfiguration,@ComponentScan.

2)、[email protected]

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {

@AliasFor(
annotation = Configuration.class
)
boolean proxyBeanMethods() default true;
}

Attention!:@ConfigurationReprésente qu'il s'agit actuellement d'une classe de configuration.

3)、[email protected]

Spécifier le paquet,Qu'est - ce queSpringNotes.

4)、[email protected]

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {
};
String[] excludeName() default {
};
}

Attention!:Analyse des priorité[email protected],@Import(AutoConfigurationImportSelector.class)

5)、[email protected]

Le nom de l'étiquette se traduit par :Paquet de configuration automatique,La règle par défaut du paquet est spécifiée.

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)//Importer un composant dans un conteneur
public @interface AutoConfigurationPackage {

String[] basePackages() default {
};
Class<?>[] basePackageClasses() default {
};
}

UtilisationRegistrarImporter une série de composants dans le conteneur
Importer tous les composants d'un paquet spécifié dans MainApplicationSous le sac.

4.2 Configuration automatique【Analyse des sources】- Chargement initial de la classe de configuration automatique

1)、 Chargement complet de la scène par défaut au démarrage

@Import(AutoConfigurationImportSelector.class)

1.UtilisationgetAutoConfigurationEntry(annotationMetadata);Importer des composants en vrac dans un conteneur

2.AppelezList configurations = getCandidateConfigurations(annotationMetadata, attributes)Obtenir toutes les classes de configuration à importer dans le conteneur

3.Chargement en usine Map<String, List> loadSpringFactories(@Nullable ClassLoader classLoader);Obtenir tous les composants

4.DeMETA-INF/spring.factoriesEmplacement pour charger un fichier.
1.Numérisation par défaut de tous les éléments de notre système actuelMETA-INF/spring.factoriesFichier de localisation
2.spring-boot-autoconfigure-2.4.4.RELEASE.jarIl y a aussiMETA-INF/spring.factories

130 Toutes les configurations automatiques pour les scénarios , Chargement complet par défaut au démarrage

[Impossible de transférer l'image de la chaîne externe,Il peut y avoir un mécanisme antivol à la station source,Il est recommandé de sauvegarder l'image et de la télécharger directement(img-pfK48taR-1641479793643)(image/image-20210326093249505.png)]

# C'est écrit dans le dossier spring-bootToutes les classes de configuration à charger dans le conteneur dès le démarrage
#spring-boot-autoconfigure-2.4.4.RELEASE.jar/META-INF/spring.factories
#Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
...

2)、 Configurer sur demande selon les règles de montage conditionnel

Bien que nous130Toutes les configurations automatiques pour les scènes sont chargées par défaut au démarrage,MaisxxxxAutoConfiguration Assembler les règles en fonction des conditions (@Conditional),Il sera finalement configuré sur demande.

Par exemple:AopAutoConfigurationCatégorie,@ConditionalOnClass(Advice.class),Non importéorg.aspectj.weaver.AdviceDépendance,EtAspectJAutoProxyingConfiguration La configuration ne prend pas effet .

Par exemple:DispatcherServletAutoConfigurationCatégorie,@ConditionalOnClass(DispatcherServlet.class),Importéspring-webmvcDépendance,EtDispatcherServletConfigurationLa configuration prendra effet.

4.3 Configuration automatique【Analyse des sources】- Processus de configuration automatique

1)、ParDispatcherServletAutoConfigurationPar exemple

ParDispatcherServletAutoConfigurationClasse interneDispatcherServletConfigurationPar exemple:

@Bean
// Ce type de composant est valide dans le conteneur 
@ConditionalOnBean(MultipartResolver.class)
//Il n'y a pas ce nom dans le conteneur multipartResolver Composants en vigueur pour 
@ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)
//Voilà[email protected] méthode dimensionnelle passe dans les paramètres de l'objet,Ce paramètreresolver La valeur est trouvée dans le conteneur .
public MultipartResolver multipartResolver(MultipartResolver resolver) {

//SpringMVC multipartResolver Empêcher certains Analyseurs de téléchargement de fichiers configurés par l'utilisateur de ne pas être conformes aux spécifications
// Detect if the user has created a MultipartResolver but named it incorrectly
//Ajout d'un analyseur de téléchargement de fichiers au conteneur
return resolver;
}

2)、 Préférences de configuration personnalisées

SpringBootPar défaut, tous les composants sont configurés au rez - de - chaussée, Mais si l'utilisateur a une configuration personnalisée , Priorité à l'utilisateur .

ParHttpEncodingAutoConfigurationPar exemple:

@Bean
//SiIOCIl n'y a pas deCharacterEncodingFilterComponents( Composants dans la classe de configuration personnalisée ),Est entré en vigueur
@ConditionalOnMissingBean
public CharacterEncodingFilter characterEncodingFilter() {

CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
filter.setEncoding(this.properties.getCharset().name());
filter.setForceRequestEncoding(this.properties.shouldForce(Encoding.Type.REQUEST));
filter.setForceResponseEncoding(this.properties.shouldForce(Encoding.Type.RESPONSE));
return filter;
}

3)、Résumé

Première étape:SpringBoot D'abord, scannez tout dans notre système actuel par défaut META-INF/spring.factoriesFichier de localisation, Charger toutes les classes de configuration automatique XxxAutoConfiguration

Deuxième étape: Chaque classe de configuration automatique XxxAutoConfiguration, Selon les conditions @ConditionalEntrée en vigueur,Configuration sur demande

Troisième étape: Classes de configuration en vigueur XxxAutoConfigurationMoyenne,Va [email protected] Assembler de nombreux composants dans le conteneur ,Tant que ces composants sont présents dans le contenant, Il aura la fonction correspondante

Quatrième étape:Configurer la classeXxxAutoConfigurationMoyenne,Il y [email protected](XxxProperties.class), Pour configurer la liaison ( Par défaut, toutes les valeurs spécifiées dans le profil sont liées )

Étape 5:XxxPropertiesDans la classe, Fournit un préfixe pour manipuler les attributs de cette classe @ConfigurationProperties(prefix = “server”)

Étape 6: Pour personnaliser la configuration ,Et:

[email protected] de configuration personnalisée,[email protected] les composants sous - jacents;

​ 2. En regardant ce composant @EnableConfigurationProperties(XxxProperties.class) Classe de configuration spécifiée ,InpropertiesUp oryaml Modifier ses propriétés sur le fichier ;

​ 3. Personnalisateur personnalisé XxxCustomizer;(Suite)

XxxAutoConfiguration —> @BeanComponents —> XxxPropertiesPrends la valeur. ----> application.properties

5.SpringBoot Comment l'application crée

Première étape:Introduction des dépendances du scénario

Documents officiels

https://docs.spring.io/spring-boot/docs/current/reference/html/using-spring-boot.html#using-boot-starter

Deuxième étape: Voir ce qui est configuré automatiquement

1.Analyse par soi - même,La configuration automatique correspondant au scénario d'introduction est généralement en vigueur

2.Dans le profildebug=trueActiver le rapport de configuration automatique.
Negative(Non valable)
Positive(Entrée en vigueur)

Troisième étape:Si des modifications sont nécessaires

1.Modifier les éléments de configuration par référence au document
Documents officielshttps://docs.spring.io/spring-boot/docs/current/reference/html/appendix-application-properties.html#common-application-properties

​ Analyse par soi - même.xxxxProperties Quelles configurations sont liées au profil .

2.Ajouter ou remplacer des composants sur mesure
@Bean、@Component…

3.Personnalisateur XXXXXCustomizer

6.Techniques de développement

6.1 LombokDéveloppement simplifié

Lombok Remplacer le constructeur par une étiquette 、getter/setter、toString() Attendez le Code des côtes de poulet .

spring boot Déjà géré Lombok.

Introduire des dépendances:

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>

IDEAMoyenneFile->Settings->Plugins,Rechercher l'installationLombokPlug - in

[Impossible de transférer l'image de la chaîne externe,Il peut y avoir un mécanisme antivol à la station source,Il est recommandé de sauvegarder l'image et de la télécharger directement(img-OhcYUM7M-1641479793644)(image/image-20210326105607057.png)]

Exemple 1:Classe d'entité

@NoArgsConstructor
//@AllArgsConstructor
@Data
@ToString
@EqualsAndHashCode
public class User {

private String name;
private Integer age;
private Pet pet;
public User(String name,Integer age){

this.name = name;
this.age = age;
}
}

Exemple 2:Simplifier le développement des journaux

@Slf4j
@RestController
public class HelloController {

@RequestMapping("/hello")
public String hello(@RequestParam("name") String name){

log.info("helloDemande....");
return "Hello, Spring Boot 2!"+"Bonjour:"+name;
}
}

6.2 dev-tools

Spring Boot includes an additional set of tools that can make the application development experience a little more pleasant. The spring-boot-devtools module can be included in any project to provide additional development-time features.——link(https://docs.spring.io/spring-boot/docs/2.3.8.RELEASE/reference/html/using-spring-boot.html#using-boot-devtools)

Applications that use spring-boot-devtools automatically restart whenever files on the classpath change. This can be a useful feature when working in an IDE, as it gives a very fast feedback loop for code changes. By default, any entry on the classpath that points to a directory is monitored for changes. Note that certain resources, such as static assets and view templates, do not need to restart the application.——link(https://docs.spring.io/spring-boot/docs/2.3.8.RELEASE/reference/html/using-spring-boot.html#using-boot-devtools-restart)

Triggering a restart

As DevTools monitors classpath resources, the only way to trigger a restart is to update the classpath. The way in which you cause the classpath to be updated depends on the IDE that you are using:

In Eclipse, saving a modified file causes the classpath to be updated and triggers a restart.
In IntelliJ IDEA, building the project (Build -> Build Project)(shortcut: Ctrl+F9) has the same effect.

Ajouter une dépendance:

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
</dependencies>

InIDEAMoyenne,Après modification du projet ou de la page:Ctrl+F9.

6.3 Spring Initailizr

Spring Initailizr(https://start.spring.io/)Est de créerSpring BootAssistant d'ingénierie.

InIDEAMoyenne,Barre de menuNew -> Project -> Spring Initailizr.

[Impossible de transférer l'image de la chaîne externe,Il peut y avoir un mécanisme antivol à la station source,Il est recommandé de sauvegarder l'image et de la télécharger directement(img-sv90zyoL-1641479793644)(image/image-20210326112303362.png)]

[Impossible de transférer l'image de la chaîne externe,Il peut y avoir un mécanisme antivol à la station source,Il est recommandé de sauvegarder l'image et de la télécharger directement(img-VnpTX3aa-1641479793645)(image/image-20210326113105487.png)]

[Impossible de transférer l'image de la chaîne externe,Il peut y avoir un mécanisme antivol à la station source,Il est recommandé de sauvegarder l'image et de la télécharger directement(img-BT9EqDiY-1641479793645)(image/image-20210326113235726.png)]

Structure du projet:

[Impossible de transférer l'image de la chaîne externe,Il peut y avoir un mécanisme antivol à la station source,Il est recommandé de sauvegarder l'image et de la télécharger directement(img-P7rA62kn-1641479793646)(image/image-20210326113820843.png)]

Trois.Profil

1.Type de profil

1.1 propertiesDocumentation

Comme avantpropertiesUtilisation

@Data
@Component
@ConfigurationProperties(prefix = "person")
public class Person {

private String name;
private boolean gender;
private Date birthday;
private List<String> hobbys;
private Car car;
private Map<String,Car> carMap;
private Map<String,List<Car>> mapList;
}
# ConfigurationPersonInformation
person.name=Zhang San
person.gender=true
person.birthday=2020/12/12
person.hobbys=[Programmation,La musique,Basketball]
person.car.label=Audi
person.car.price=200000.0
# Map<String,Car>
person.car-map.AAA.label=Benz!
person.car-map.AAA.price=500000.0
# Map<String,List<Car>>
person.map-list.BBB[0].label=Volvo
person.map-list.BBB[0].price=600000.0
person.map-list.BBB[1].label=BYD.
person.map-list.BBB[1].price=500000.0
@SpringBootTest
class SpringbootCh03ConfigApplicationTests {

@Autowired
private Person person;
@Test
void contextLoads() {

System.out.println(person);
}
}

1.2 YAMLUtilisation de

YAML - Oui. “YAML Ain’t Markup Language”(YAML Pas un langage de balisage)Abréviation récursive de.Dans le développement de cette langue,,YAML En fait, ça veut dire:“Yet Another Markup Language”(Reste un langage de balisage).

Idéal pour les profils centrés sur les données.

1)、Syntaxe de base

key: value;kvEspace entre

Sensible à la casse

Utiliser l'indentation pour représenter les relations hiérarchiques

Indentation non autoriséetab,Seuls les espaces sont autorisés

Le nombre d'espaces indentés n'est pas important,Tant que les éléments du même niveau sont alignés à gauche

'#'Représente un commentaire

La chaîne n'a pas besoin de guillemets,Si vous voulez ajouter,Guillemets simples’’、Guillemets doubles"" Indique que le contenu de la chaîne sera évasion / Ne pas fuir

2)、Type de données

Quantité littérale:Unique、Valeur non séparable.date、boolean、string、number、null

k: v

Objet:Ensemble de paires de valeurs clés.map、hash、object

#écriture en ligne: 
k: {
k1: v1,k2: v2,k3: v3}
#Ou
k:
k1: v1
k2: v2
k3: v3

Tableau:Un ensemble de valeurs dans l'ordre.array、list、queue、set

#écriture en ligne: 
k: [v1,v2,v3]
#Ou
k:
- v1
- v2
- v3

3)、Exemple

@Data
public class Person {

private String userName;
private Boolean boss;
private Date birth;
private Integer age;
private Pet pet;
private String[] interests;
private List<String> animal;
private Map<String, Object> score;
private Set<Double> salarys;
private Map<String, List<Pet>> allPets;
}
@Data
public class Pet {

private String name;
private Double weight;
}

AvecyamlReprésente l'objet ci - dessus

person:
userName: zhangsan
boss: false
birth: 2019/12/12 20:12:33
age: 18
pet:
name: tomcat
weight: 23.4
interests: [Basketball,Nager]
animal:
- jerry
- mario
score:
english:
first: 30
second: 40
third: 50
math: [131,140,148]
chinese: {
first: 128,second: 136}
salarys: [3999,4999.98,5999.99]
allPets:
sick:
- {
name: tom}
- {
name: jerry,weight: 47}
health: [{
name: mario,weight: 47}]

2.Conseils de configuration pour personnaliser la liaison de classe

You can easily generate your own configuration metadata file from items annotated with @ConfigurationProperties by using the spring-boot-configuration-processor jar. The jar includes a Java annotation processor which is invoked as your project is compiled.——link(https://docs.spring.io/spring-boot/docs/2.4.2/reference/htmlsingle/#configuration-metadata-annotation-processor)

Les liens personnalisés de classe et de profil ne sont généralement pas sollicités. Pour un rappel ,Ajouter les dépendances suivantes:

<!-- Les classes personnalisées et les liens de profil sont invités -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- Le plug - in suivant est utilisé lorsque le projet est emballé ,Non.spring-boot-configuration-processor Dans le sac , Pour qu'il ne fonctionne que lorsqu'il est encodé -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>

3.Exercices en classe

public class Person {

//Quantité littérale: String Taille Temps Boole
private String name;
private Integer age;
private Date birthday;
private Boolean flag;
//Objet、Map : Paire de clés
private Car car;
private Map<String,Object> maps;
//Tableau(List、Set) : Un ensemble de valeurs
private List<String> list;
private List<Object> listObj;
//Structure Composite
private List<Car> listCars;
private List<Map<String,Object>> listMap;
private Map<String,List<Object>> mapList;
}
public class Car {

private String name;
private Double price;
}

Exigences1:UtiliserpropertiesDocumentation, Compléter la liaison personnalisée des classes et des profils

Exigences2:UtiliseryamlDocumentation, Compléter la liaison personnalisée des classes et des profils

Quatre.WebDéveloppement

webIntroduction au développement

Spring Boot provides auto-configuration for Spring MVC that works well with most applications.

(La plupart des scénarios ne nécessitent pas de configuration personnalisée)

The auto-configuration adds the following features on top of Spring’s defaults:

1.Inclusion of ContentNegotiatingViewResolver and BeanNameViewResolver beans.

Content Negotiation View Parser etBeanNameVoir l'analyseur

2.Support for serving static resources, including support for WebJars (covered later in this document)).

Ressources statiques(Y compris:webjars)

3.Automatic registration of Converter, GenericConverter, and Formatter beans.

Inscription automatique Converter,GenericConverter,Formatter

4.Support for HttpMessageConverters (covered later in this document).

Soutien HttpMessageConverters

5.Automatic registration of MessageCodesResolver (covered later in this document).

Inscription automatique MessageCodesResolver (Pour l'internationalisation)

6.Static index.html support.

Statiqueindex.html Support de page

7.Custom Favicon support (covered later in this document).

Personnalisation Favicon

8.Automatic use of a ConfigurableWebBindingInitializer bean (covered later in this document).

Utilisation automatique ConfigurableWebBindingInitializer ,(DataBinderResponsable de la liaison des données demandées àJavaBeanAllez.)

If you want to keep those Spring Boot MVC customizations and make more MVC customizations (interceptors, formatters, view controllers, and other features), you can add your own @Configuration class of type WebMvcConfigurer but without @EnableWebMvc.

Non, [email protected] @Configuration + WebMvcConfigurer Règles personnalisées

If you want to provide custom instances of RequestMappingHandlerMapping, RequestMappingHandlerAdapter, or ExceptionHandlerExceptionResolver, and still keep the Spring Boot MVC customizations, you can declare a bean of type WebMvcRegistrations and use it to provide custom instances of those components.

Déclaration WebMvcRegistrations Modifier les composants sous - jacents par défaut

If you want to take complete control of Spring MVC, you can add your own @Configuration annotated with @EnableWebMvc, or alternatively add your own @Configuration-annotated DelegatingWebMvcConfiguration as described in the Javadoc of @EnableWebMvc.

Utiliser @[email protected]+DelegatingWebMvcConfiguration Prise en charge complèteSpringMVC

1.Ressources statiques

1.1 Règles de ressources statiques et personnalisation

1)、Répertoire des ressources statiques

Tant que les ressources statiques sont placées sous le chemin de classe: /static (or /public or /resources or /META-INF/resources)

Chemin d'accès : Chemin racine actuel du projet/ + Nom de la ressource statique

**Principes: Cartographie statique/****.

Demande d'entrer.,Trouve - le d'abord.ControllerVoyez si vous pouvez gérer.SiControllerImpossible de gérer, Ensuite, la demande est retournée au gestionnaire de ressources statiques .Réponse si la ressource statique n'est pas trouvée404Page.

2)、Préfixe d'accès aux ressources statiques

# Pas de préfixe par défaut lors de l'accès aux ressources statiques , Vous pouvez modifier le chemin du préfixe pour l'accès statique aux ressources , Lors de l'accès :http://localhost:8899/res/Nom de la ressource
spring:
mvc:
static-path-pattern: /res/**
# Modifier le nom de dossier par défaut de la ressource statique ,Jean/static,/public , /resources , /META-INF/resourcesÉchec
web:
resources:
static-locations: [classpath:/abc/]

Chemin racine actuel du projet + static-path-pattern + Nom de la ressource statique = Rechercher sous le dossier des ressources statiques

3)、webjars

Cartographie automatique /webjars/**

DisponiblejarComment ajoutercss,jsFichiers de ressources égales,https://www.webjars.org/

Par exemple,AjouterjqueryDewebjarsDépendance vis - à - vis des ressources: VoirjarSac,Ressources disponibles /META-INF/resourcesSous le dossier

<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.5.1</version>
</dependency>

Adresse d'accès:http://localhost:8080/webjars/jquery/3.5.1/jquery.js L'adresse suivante suit le chemin du paquet à l'intérieur de la dépendance.

1.2 welcomeAvecfaviconFonction

1)、Support de la page d'accueil

Mode 1:Sous le chemin des ressources statiques index.html

Attention!:Les chemins de ressources statiques peuvent être configurés,Mais vous ne pouvez pas configurer le préfixe d'accès pour les ressources statiques.Sinon, il en résulte index.htmlImpossible d'accéder par défaut

spring:
# mvc:
# static-path-pattern: /res/** Ça mène àwelcome pageDéfaillance fonctionnelle
resources:
static-locations: [classpath:/abc/]

Mode 2:controllerÇa marche./index

2)、PersonnalisationFavicon

Petite icône sur l'étiquette de la page .

favicon.ico Il suffit de le placer dans le répertoire des ressources statiques.

spring:
# mvc:
# static-path-pattern: /res/** Ça mène à Favicon Défaillance fonctionnelle

1.3 【Analyse des sources】- Principe de la règle des ressources statiques

SpringBootDémarrer le chargement par défaut xxxAutoConfiguration Catégorie(Classe de configuration automatique)

SpringMVCClasse de configuration automatique des fonctions==WebMvcAutoConfiguration==,Entrée en vigueur

@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({
 Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({
 DispatcherServletAutoConfiguration.class,
TaskExecutionAutoConfiguration.class,
ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {

}

WebMvcAutoConfigurationAdapter Contenu configuré pour le conteneur :

@Configuration(proxyBeanMethods = false)
@Import(EnableWebMvcConfiguration.class)
@EnableConfigurationProperties({
 WebMvcProperties.class, ResourceProperties.class })
@Order(0)
public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {

...
}

Liaison des propriétés associées au profil :WebMvcProperties==spring.mvc、ResourceProperties==spring.resources

La classe de configuration n'a qu'un seul constructeur de paramètres

Les valeurs de tous les paramètres du constructeur paramétrique sont déterminées à partir du conteneur

//Les valeurs de tous les paramètres du constructeur paramétrique sont déterminées à partir du conteneur
//ResourceProperties resourceProperties;Accès etspring.resourcesObjet de toutes les valeurs liées
//WebMvcProperties mvcProperties Accès etspring.mvcObjet de toutes les valeurs liées
//ListableBeanFactory beanFactory SpringDebeanFactory
//HttpMessageConverters Trouver toutHttpMessageConverters
//ResourceHandlerRegistrationCustomizer Trouver Personnalisation du gestionnaire de ressources.=========
//DispatcherServletPath 
//ServletRegistrationBean Enregistrer la demandeServlet、Filter....
public WebMvcAutoConfigurationAdapter(
ResourceProperties resourceProperties,
WebMvcProperties mvcProperties,
ListableBeanFactory beanFactory,
ObjectProvider<HttpMessageConverters> messageConvertersProvider,
ObjectProvider<ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider,
ObjectProvider<DispatcherServletPath> dispatcherServletPath,
ObjectProvider<ServletRegistrationBean<?>> servletRegistrations) {

this.resourceProperties = resourceProperties;
this.mvcProperties = mvcProperties;
this.beanFactory = beanFactory;
this.messageConvertersProvider = messageConvertersProvider;
this.resourceHandlerRegistrationCustomizer = resourceHandlerRegistrationCustomizerProvider.getIfAvailable();
this.dispatcherServletPath = dispatcherServletPath;
this.servletRegistrations = servletRegistrations;
}

1)、Règles par défaut pour le traitement des ressources

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {

if (!this.resourceProperties.isAddMappings()) {

logger.debug("Default resource handling disabled");
return;
}
Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
//webjarsRègles
if (!registry.hasMappingForPattern("/webjars/**")) {

customizeResourceHandlerRegistration(registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/") .setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
}
// Règles par défaut pour les chemins d'accès statiques aux ressources 
String staticPathPattern = this.mvcProperties.getStaticPathPattern();
if (!registry.hasMappingForPattern(staticPathPattern)) {

customizeResourceHandlerRegistration(registry.addResourceHandler(staticPathPattern)
.addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations()))
.setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
}
}

Selon le code ci - dessus, Nous pouvons désactiver toutes les règles de ressources statiques avec la même configuration .

spring:
# mvc:
# static-path-pattern: /res/**
web:
resources:
add-mappings: false # Désactiver le chemin d'accès statique par défaut aux ressources 

Règles relatives aux ressources statiques :

@ConfigurationProperties(prefix = "spring.resources", ignoreUnknownFields = false)
public class ResourceProperties {

private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {
 "classpath:/META-INF/resources/",
"classpath:/resources/", "classpath:/static/", "classpath:/public/" };
/** * Locations of static resources. Defaults to classpath:[/META-INF/resources/, * /resources/, /static/, /public/]. */
private String[] staticLocations = CLASSPATH_RESOURCE_LOCATIONS;

2)、Règles de traitement de la page d'accueil

//HandlerMapping:Carte du processeur.Chacun a été sauvegardéHandlerQuelles demandes peuvent être traitées. 
@Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext,FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {

WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(
new TemplateAvailabilityProviders(applicationContext), applicationContext, getWelcomePage(),
this.mvcProperties.getStaticPathPattern());
welcomePageHandlerMapping.setInterceptors(getInterceptors(mvcConversionService, mvcResourceUrlProvider));
welcomePageHandlerMapping.setCorsConfigurations(getCorsConfigurations());
return welcomePageHandlerMapping;
}
//WelcomePageHandlerMapping
WelcomePageHandlerMapping(TemplateAvailabilityProviders templateAvailabilityProviders,
ApplicationContext applicationContext,
Optional<Resource> welcomePage, String staticPathPattern) {

if (welcomePage.isPresent() && "/**".equals(staticPathPattern)) {

//Pour utiliser la fonction page d'accueil,Ça doit l'être./**
logger.info("Adding welcome page: " + welcomePage.get());
setRootViewName("forward:index.html");
}
else if (welcomeTemplateExists(templateAvailabilityProviders, applicationContext)) {

// AppelezController /index
logger.info("Adding welcome page template: index");
setRootViewName("index");
}
}

Le Code dans cette méthode de construction explique également webScénario-welcomeAvecfavicon Configuré en fonction static-path-patternC'est,welcome Problèmes avec les pages et les petites icônes invalidées .

2.Traitement des demandes

2.1 RestDemande de cartographie

1)、Demande de cartographie

RestSupport stylistique(UtiliserHTTPDemander un verbe pour représenter une action sur une ressource)

Avant:
/getUser Obtenir l'utilisateur
/deleteUser Supprimer l'utilisateur
/editUser Modifier l'utilisateur
/saveUserEnregistrer l'utilisateur

Maintenant: /user
GET-Obtenir l'utilisateur
DELETE-Supprimer l'utilisateur
PUT-Modifier l'utilisateur
POST-Enregistrer l'utilisateur

@XxxMapping; Remplacer @RequestMapping(value = “/rest”,method= RequestMethod.XXX)

@GetMapping
@PostMapping
@PutMapping
@DeleteMapping

CoreFilter:HiddenHttpMethodFilter MoyennedoFilterInternal()Exécuter la logique du filtre

2)、Utilisation

Première étape:Ouvrir le formulaire de pageRestFonction

Page formPropriétés demethod=post,Masquer les champs _method=put、deleteAttendez.(Si directementgetOupost, Pas besoin de cacher le domaine )

<form action="/user" method="get">
<input value="REST-GETSoumettre" type="submit" />
</form>
<form action="/user" method="post">
<input value="REST-POSTSoumettre" type="submit" />
</form>
<form action="/user" method="post">
<input name="_method" type="hidden" value="DELETE"/>
<input value="REST-DELETESoumettre" type="submit"/>
</form>
<form action="/user" method="post">
<input name="_method" type="hidden" value="PUT" />
<input value="REST-PUTSoumettre"type="submit" />
<form>
Deuxième étape:ControllerDemande de cartographie
@GetMapping("/user")
//@RequestMapping(value = "/user",method = RequestMethod.GET)
public String getUser(){

return "GET-Zhang San";
}
@PostMapping("/user")
//@RequestMapping(value = "/user",method = RequestMethod.POST)
public String saveUser(){

return "POST-Zhang San";
}
@PutMapping("/user")
//@RequestMapping(value = "/user",method = RequestMethod.PUT)
public String putUser(){

return "PUT-Zhang San";
}
@DeleteMapping("/user")
//@RequestMapping(value = "/user",method = RequestMethod.DELETE)
public String deleteUser(){

return "DELETE-Zhang San";
}
Troisième étape: Modifier la configuration par défaut activer le support PUT、DELETEMéthode de traitement des demandes
# Ouvrir le formulaire de pageRestFonction(SoutienPUT、DELETE)
spring.mvc.hiddenmethod.filter.enabled=true

3)、RestPrincipes(Formulaire soumis pour utilisationRESTQuand)

1.Les formulaires sont soumis avec _method=PUT

2.Demande de venir.HiddenHttpMethodFilterInterception

3.La demande est - elle correcte?,Et oui.POST

4.Obtenir_methodValeur de

5.Compatible avec les demandes suivantes:PUT.DELETE.PATCH

6.Primitiverequest(post),Mode d'emballagerequesWrapperRéécritgetMethodMéthodes,Renvoie la valeur passée.

7.Utilisé lorsque la chaîne de filtres est libéréewrapper.Appels de méthode ultérieursgetMethodC'est un appel.requesWrapperDe.

public class HiddenHttpMethodFilter extends OncePerRequestFilter {

private static final List<String> ALLOWED_METHODS =
Collections.unmodifiableList(Arrays.asList(
HttpMethod.PUT.name(),
HttpMethod.DELETE.name(),
HttpMethod.PATCH.name()));
/** Default method parameter: {@code _method}. */
public static final String DEFAULT_METHOD_PARAM = "_method";
private String methodParam = DEFAULT_METHOD_PARAM;
/** * Set the parameter name to look for HTTP methods. * @see #DEFAULT_METHOD_PARAM */
public void setMethodParam(String methodParam) {

Assert.hasText(methodParam, "'methodParam' must not be empty");
this.methodParam = methodParam;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {

HttpServletRequest requestToUse = request;
if ("POST".equals(request.getMethod()) && request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) == null) {

String paramValue = request.getParameter(this.methodParam);
if (StringUtils.hasLength(paramValue)) {

String method = paramValue.toUpperCase(Locale.ENGLISH);
if (ALLOWED_METHODS.contains(method)) {

requestToUse = new HttpMethodRequestWrapper(request, method);
}
}
}
filterChain.doFilter(requestToUse, response);
}
/** * Simple {@link HttpServletRequest} wrapper that returns the supplied method for * {@link HttpServletRequest#getMethod()}. */
private static class HttpMethodRequestWrapper extends HttpServletRequestWrapper {

private final String method;
public HttpMethodRequestWrapper(HttpServletRequest request, String method) {

super(request);
this.method = method;
}
@Override
public String getMethod() {

return this.method;
}
}
}

4)、RestUtilisation des outils clients

Par exemple:PostMan Peut être envoyé directement put、deleteDemande par exemple.

5)、Comment changer par défaut_method

@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({
 Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({
 DispatcherServletAutoConfiguration.class,
TaskExecutionAutoConfiguration.class,
ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {

...
@Bean
@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)
@ConditionalOnProperty(prefix = "spring.mvc.hiddenmethod.filter", name = "enabled", matchIfMissing = false)
public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {

return new OrderedHiddenHttpMethodFilter();
}
...
}

**@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)** Ça veut dire qu'il n'y a pas de HiddenHttpMethodFilterHeure,Juste pour exécuterhiddenHttpMethodFilter().Donc,,Nous pouvons personnaliserfilter,Modifier par défaut_method.

Classe de configuration personnalisée,Par exemple:

@Configuration(proxyBeanMethods = false)
public class WebConfig{

//Personnalisationfilter
@Bean
public HiddenHttpMethodFilter hiddenHttpMethodFilter(){

HiddenHttpMethodFilter methodFilter = new HiddenHttpMethodFilter();
methodFilter.setMethodParam("_m");
return methodFilter;
}
}

Mettez_methodModifier comme suit:_m

<form action="/user" method="post">
<input name="_m" type="hidden" value="DELETE"/>
<input value="REST-DELETE Soumettre" type="submit"/>
</form>

2.2 【Analyse des sources】-Principe de la cartographie des demandes

[Impossible de transférer l'image de la chaîne externe,Il peut y avoir un mécanisme antivol à la station source,Il est recommandé de sauvegarder l'image et de la télécharger directement(img-kVvU9Z28-1641479793647)(image/8.jpg)]

SpringMVCL'analyse fonctionnelle a été effectuée à partir de org.springframework.web.servlet.DispatcherServlet -> doDispatch()

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {

HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {

ModelAndView mv = null;
Exception dispatchException = null;
try {

processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Trouver lequel utiliser pour la demande actuelleHandler(ControllerMéthode)Traitement
mappedHandler = getHandler(processedRequest);
//HandlerMapping:Carte du processeur./xxx->>xxxx
...
}

this.handlerMappingsInDebug Contenu affiché en mode :

[Impossible de transférer l'image de la chaîne externe,Il peut y avoir un mécanisme antivol à la station source,Il est recommandé de sauvegarder l'image et de la télécharger directement(img-M2TKCE8q-1641479793648)(image/image-20210329092643375.png)]

RequestMappingHandlerMapping: Parmi eux,Tout est sauvegardé@RequestMapping EthandlerRègles de cartographie pour.

mapping --> mappingRegistry --> mappingLookup

Toutes les cartes des demandes sontHandlerMappingMoyenne:

1.SpringBootConfigurer automatiquement la page d'accueil WelcomePageHandlerMapping .Accès à /Accèsindex.html;

2.SpringBootPar défaut configuré automatiquement De RequestMappingHandlerMapping

3.Demande d'entrer.,Essayez tout un par un.HandlerMappingVoir s'il y a des informations demandées.

​ Si c'est le cas, trouvez la réponse à cette demandehandler

​ Si ce n'est pas le cas, c'est le prochain HandlerMapping

4.Nous avons besoin d'un traitement de cartographie personnalisé,On peut aussi mettreHandlerMapping.Personnalisation HandlerMapping

getHandler()La méthode est la suivante::

@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {

if (this.handlerMappings != null) {

for (HandlerMapping mapping : this.handlerMappings) {

HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {

return handler;
}
}
}
return null;
}

IDEARaccourcis clavier:

  • Ctrl + Alt + U : ParUML Le diagramme de classe montre quelles classes héritées la classe a , Classes dérivées et interfaces implémentées .
  • Crtl + Alt + Shift + U : Ibid., La différence est que le résultat du raccourci précédent apparaît sur la nouvelle page , Et les résultats de ce raccourci clavier sont affichés dans le pop - up .
  • Ctrl + H : Afficher la hiérarchie des classes sous forme d'arbre .

2.3 Commentaires sur les paramètres

Notes:

@PathVariable Variable de chemin
@RequestHeader Obtenir l'en - tête de la demande
@RequestParam Obtenir les paramètres de la requête( Paramètre après le point d'interrogation ,url?a=1&b=2)
@CookieValue AccèsCookieValeur
@RequestAttribute AccèsrequestPropriétés du domaine
@RequestBody Obtenir le corps de la demande[POST]
@MatrixVariable Variables matricielles
@ModelAttribute Variables dans le champ de requête

1)、@PathVariable Variable de chemin

@RestController
public class ParamController {

/** * [email protected] Variable de chemin * Chemin d'accès http://localhost:8899/testPath/zs/123 * * Dans le chemin de la demande "/testPath/{name}/{pwd}" {}Placeholder, * [email protected] Annotation pour obtenir la valeur du paramètre de requête à l'emplacement correspondant * * @PathVariable Map<String,String> pv Obtenir directement le chemin de la demande , Toutes les variables de chemin */
@GetMapping("/testPath/{name}/{pwd}")
@ResponseBody
public Map<String,Object> testPathVariable(
@PathVariable("name") String username,
@PathVariable("pwd") String password,
@PathVariable Map<String,String> pv){

Map<String,Object> map = new HashMap<>();
map.put("username",username);
map.put("password",password);
map.put("pv",pv);
return map;
}
}

PostmanTests:

[Impossible de transférer l'image de la chaîne externe,Il peut y avoir un mécanisme antivol à la station source,Il est recommandé de sauvegarder l'image et de la télécharger directement(img-LoPq1Jdt-1641479793648)(image/image-20210327170157336.png)]

2)、@RequestParam Obtenir les paramètres de la requête

/** * [email protected] Obtenir les paramètres de la requête * Adresse demandée /testParam/{id}?sex=0&pwd=123&pwd=456 Effectuer des visites * ?sex=0&pwd=123&pwd=456 À [email protected]ètres de traitement de la demande * * @RequestParam MultiValueMap<String,String> params Obtenir les valeurs de tous les paramètres de requête */
@GetMapping("/testParam/{id}")
@ResponseBody
public Map<String,Object> testRequestParam(
@PathVariable("id") Integer id,
@RequestParam("sex") String sex,
@RequestParam("pwd") List<String> pwd,
@RequestParam MultiValueMap<String,String> params){

Map<String,Object> map = new HashMap<>();
map.put("id",id);
map.put("sex",sex);
map.put("pwd",pwd);
map.put("params",params);
return map;
}

PostmanTests:

[Impossible de transférer l'image de la chaîne externe,Il peut y avoir un mécanisme antivol à la station source,Il est recommandé de sauvegarder l'image et de la télécharger directement(img-ba1negXc-1641479793649)(image/image-20210327172116091.png)]

3)、@RequestAttribute AccèsrequestPropriétés du domaine

/** * [email protected] AccèsrequestPropriétés du domaine */
@GetMapping("/testAttr/{id}")
public String testRequestAttr(
@PathVariable("id")Integer id ,
HttpServletRequest request){

// Définir les valeurs des attributs dans le champ de requête 
request.setAttribute("idNew",id);
//Demande de transmission, Poursuivre la demande actuelle , Porter les données demandées 
return "forward:/success";
}
@GetMapping("/success")
@ResponseBody
public Map<String,Object> testSuccess(
@RequestAttribute("idNew") Integer id){

Map<String,Object> map = new HashMap<>();
map.put("idNew",id);
return map;
}

Tests:

[Impossible de transférer l'image de la chaîne externe,Il peut y avoir un mécanisme antivol à la station source,Il est recommandé de sauvegarder l'image et de la télécharger directement(img-qEluceTp-1641479793649)(image/image-20210327164619132.png)]

4)、@RequestBody Obtenir le corps de la demande

/** * [email protected] Obtenir le corps de la demande */
@PostMapping("/add")
@ResponseBody
public Map<String,Object> add(@RequestBody String data){

Map<String,Object> map = new HashMap<>();
map.put("data",data);
return map;
}

Tests:

PostmanTests

[Impossible de transférer l'image de la chaîne externe,Il peut y avoir un mécanisme antivol à la station source,Il est recommandé de sauvegarder l'image et de la télécharger directement(img-HhyzZEMi-1641479793650)(image/image-20210703174714347.png)]

Test du navigateur:

[Impossible de transférer l'image de la chaîne externe,Il peut y avoir un mécanisme antivol à la station source,Il est recommandé de sauvegarder l'image et de la télécharger directement(img-n3MkAM1N-1641479793650)(image/image-20210327165419922.png)]

2.4 Servlet APIParamètres

WebRequest
ServletRequest
MultipartRequest
HttpSession
javax.servlet.http.PushBuilder
Principal
InputStream
Reader
HttpMethod
Locale
TimeZone
ZoneId

ServletRequestMethodArgumentResolver Utilisé pour traiter les paramètres ci - dessus

public class ServletRequestMethodArgumentResolver implements HandlerMethodArgumentResolver {

@Nullable
private static Class<?> pushBuilder;
static {

try {

pushBuilder = ClassUtils.forName("javax.servlet.http.PushBuilder",
ServletRequestMethodArgumentResolver.class.getClassLoader());
}
catch (ClassNotFoundException ex) {

// Servlet 4.0 PushBuilder not found - not supported for injection
pushBuilder = null;
}
}
@Override
public boolean supportsParameter(MethodParameter parameter) {

Class<?> paramType = parameter.getParameterType();
return (WebRequest.class.isAssignableFrom(paramType) ||
ServletRequest.class.isAssignableFrom(paramType) ||
MultipartRequest.class.isAssignableFrom(paramType) ||
HttpSession.class.isAssignableFrom(paramType) ||
(pushBuilder != null && pushBuilder.isAssignableFrom(paramType)) ||
(Principal.class.isAssignableFrom(paramType) && !parameter.hasParameterAnnotations()) ||
InputStream.class.isAssignableFrom(paramType) ||
Reader.class.isAssignableFrom(paramType) ||
HttpMethod.class == paramType ||
Locale.class == paramType ||
TimeZone.class == paramType ||
ZoneId.class == paramType);
}
@Override
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {

Class<?> paramType = parameter.getParameterType();
// WebRequest / NativeWebRequest / ServletWebRequest
if (WebRequest.class.isAssignableFrom(paramType)) {

if (!paramType.isInstance(webRequest)) {

throw new IllegalStateException(
"Current request is not of type [" + paramType.getName() + "]: " + webRequest);
}
return webRequest;
}
// ServletRequest / HttpServletRequest / MultipartRequest / MultipartHttpServletRequest
if (ServletRequest.class.isAssignableFrom(paramType) || MultipartRequest.class.isAssignableFrom(paramType)) {

return resolveNativeRequest(webRequest, paramType);
}
// HttpServletRequest required for all further argument types
return resolveArgument(paramType, resolveNativeRequest(webRequest, HttpServletRequest.class));
}
private <T> T resolveNativeRequest(NativeWebRequest webRequest, Class<T> requiredType) {

T nativeRequest = webRequest.getNativeRequest(requiredType);
if (nativeRequest == null) {

throw new IllegalStateException(
"Current request is not of type [" + requiredType.getName() + "]: " + webRequest);
}
return nativeRequest;
}
@Nullable
private Object resolveArgument(Class<?> paramType, HttpServletRequest request) throws IOException {

if (HttpSession.class.isAssignableFrom(paramType)) {

HttpSession session = request.getSession();
if (session != null && !paramType.isInstance(session)) {

throw new IllegalStateException(
"Current session is not of type [" + paramType.getName() + "]: " + session);
}
return session;
}
else if (pushBuilder != null && pushBuilder.isAssignableFrom(paramType)) {

return PushBuilderDelegate.resolvePushBuilder(request, paramType);
}
else if (InputStream.class.isAssignableFrom(paramType)) {

InputStream inputStream = request.getInputStream();
if (inputStream != null && !paramType.isInstance(inputStream)) {

throw new IllegalStateException(
"Request input stream is not of type [" + paramType.getName() + "]: " + inputStream);
}
return inputStream;
}
else if (Reader.class.isAssignableFrom(paramType)) {

Reader reader = request.getReader();
if (reader != null && !paramType.isInstance(reader)) {

throw new IllegalStateException(
"Request body reader is not of type [" + paramType.getName() + "]: " + reader);
}
return reader;
}
else if (Principal.class.isAssignableFrom(paramType)) {

Principal userPrincipal = request.getUserPrincipal();
if (userPrincipal != null && !paramType.isInstance(userPrincipal)) {

throw new IllegalStateException(
"Current user principal is not of type [" + paramType.getName() + "]: " + userPrincipal);
}
return userPrincipal;
}
else if (HttpMethod.class == paramType) {

return HttpMethod.resolve(request.getMethod());
}
else if (Locale.class == paramType) {

return RequestContextUtils.getLocale(request);
}
else if (TimeZone.class == paramType) {

TimeZone timeZone = RequestContextUtils.getTimeZone(request);
return (timeZone != null ? timeZone : TimeZone.getDefault());
}
else if (ZoneId.class == paramType) {

TimeZone timeZone = RequestContextUtils.getTimeZone(request);
return (timeZone != null ? timeZone.toZoneId() : ZoneId.systemDefault());
}
// Should never happen...
throw new UnsupportedOperationException("Unknown parameter type: " + paramType.getName());
}
/** * Inner class to avoid a hard dependency on Servlet API 4.0 at runtime. */
private static class PushBuilderDelegate {

@Nullable
public static Object resolvePushBuilder(HttpServletRequest request, Class<?> paramType) {

PushBuilder pushBuilder = request.newPushBuilder();
if (pushBuilder != null && !paramType.isInstance(pushBuilder)) {

throw new IllegalStateException(
"Current push builder is not of type [" + paramType.getName() + "]: " + pushBuilder);
}
return pushBuilder;
}
}
}

2.5 Paramètres complexes

Map

Model(map、modelLes données à l'intérieur seront placées dansrequestDomaine de demande pour request.setAttribute)

RedirectAttributes( Rediriger les données de transport)

ServletResponse(responseRéponse)

Errors/BindingResult

SessionStatus

UriComponentsBuilder

ServletUriComponentsBuilder

1)、Model、MapCAS (requestDomaine de la demande)

map、modelLes données à l'intérieur seront placées dansrequestDomaine de demande pour request.setAttribute

@Controller
public class ModelMapController {

/** * Paramètres suivants, Les deux mettent les données dans le champ de demande * @param map * @param model * @param modelMap * @param request * @return */
@GetMapping(value = "/modelAdd")
public String modelAdd(
Map<String,String> map ,
Model model,
ModelMap modelMap,
HttpServletRequest request){

// Les données sont placées dans le champ de demande ci - dessous 
map.put("k1","map&v1");
model.addAttribute("k2","model&v2");
modelMap.addAttribute("k3","modelMap&v3");
request.setAttribute("k4","request&v4");
// Maintenir la demande originale , Les données du champ de demande peuvent être transférées à successMoyenne
return "redirect:/modelSuccess";
}
@GetMapping("/modelSuccess")
@ResponseBody
public Map<String,Object> modelSuccess(HttpServletRequest request){

Map<String,Object> map = new HashMap<>();
// Obtenir les propriétés de la requête à partir du champ de requête 
Object v1 = request.getAttribute("k1");
Object v2 = request.getAttribute("k2");
Object v3 = request.getAttribute("k3");
Object v4 = request.getAttribute("k4");
//Ajouter àmapEnsemble
map.put("map",v1);
map.put("model",v2);
map.put("modelMap",v3);
map.put("request",v4);
return map;
}
}
  • Map map
  • Model model
  • HttpServletRequest request

Tous les trois peuvent donner requestMettre les données dans le champ,Avecrequest.getAttribute()Accès

2)、ServletResponseCAS(responseRéponse)

@Controller
public class ModelMapController {

/** * Paramètres suivants, Les deux mettent les données dans le champ de demande * @param map * @param model * @param modelMap * @param request * @param response * @return */
@GetMapping(value = "/modelAdd")
public String modelAdd(
Map<String,String> map ,
Model model,
ModelMap modelMap,
HttpServletRequest request,
HttpServletResponse response){

// Les données sont placées dans le champ de demande ci - dessous 
map.put("k1","map&v1");
model.addAttribute("k2","model&v2");
modelMap.addAttribute("k3","modelMap&v3");
request.setAttribute("k4","request&v4");
//AjouterCookie, Vous pouvez voir l'ajout de cookie
Cookie cookie = new Cookie("kaaa","vaaa");
response.addCookie(cookie);
// Maintenir la demande originale , Les données du champ de demande peuvent être transférées à successMoyenne
return "redirect:/modelSuccess";
}
@GetMapping("/modelSuccess")
@ResponseBody
public Map<String,Object> modelSuccess(HttpServletRequest request){

Map<String,Object> map = new HashMap<>();
// Obtenir les propriétés de la requête à partir du champ de requête 
Object v1 = request.getAttribute("k1");
Object v2 = request.getAttribute("k2");
Object v3 = request.getAttribute("k3");
Object v4 = request.getAttribute("k4");
//Ajouter àmapEnsemble
map.put("map",v1);
map.put("model",v2);
map.put("modelMap",v3);
map.put("request",v4);
return map;
}
}

3)、RedirectAttributesCAS( Rediriger les données de transport)

@Controller
public class RedirectAttributesController {

//Lors de la redirection, Forcer l'ajout des paramètres de la demande 
@RequestMapping("/addRedirectAttributes")
public String addRedirectAttributes(RedirectAttributes redirectAttributes){

// Réponse à la redirection , Forcer les paramètres de demande ajoutés http://localhost:8899/successRedirectAttributes?kk1=vv1&kk2=vv2
redirectAttributes.addAttribute("kk1","vv1");
redirectAttributes.addAttribute("kk2","vv2");
return "redirect:/successRedirectAttributes";
}
@RequestMapping("/successRedirectAttributes")
@ResponseBody
public Map<String,Object> successRedirectAttributes(@RequestParam Map maps){

Map<String,Object> map = new HashMap<>();
map.put("maps",maps);
return map;
}
}

Tests: http://localhost:8899/addRedirectAttributes

[Impossible de transférer l'image de la chaîne externe,Il peut y avoir un mécanisme antivol à la station source,Il est recommandé de sauvegarder l'image et de la télécharger directement(img-qTzlMD75-1641479793651)(image/image-20210329140823210.png)]

4)、【Analyse des sources】

Ensuite, regardons,Map mapAvecModel model Avec quel processeur de paramètres .

Map mapParamètresMapMethodProcessorTraitement:

public class MapMethodProcessor implements HandlerMethodArgumentResolver, HandlerMethodReturnValueHandler {

@Override
public boolean supportsParameter(MethodParameter parameter) {

return (Map.class.isAssignableFrom(parameter.getParameterType()) &&
parameter.getParameterAnnotations().length == 0);
}
@Override
@Nullable
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {

Assert.state(mavContainer != null, "ModelAndViewContainer is required for model exposure");
return mavContainer.getModel();
}
...
}

mavContainer.getModel()Comme suit:

public class ModelAndViewContainer {

...
private final ModelMap defaultModel = new BindingAwareModelMap();
@Nullable
private ModelMap redirectModel;
...
public ModelMap getModel() {

if (useDefaultModel()) {

return this.defaultModel;
}
else {

if (this.redirectModel == null) {

this.redirectModel = new ModelMap();
}
return this.redirectModel;
}
}
private boolean useDefaultModel() {

return (!this.redirectModelScenario || (this.redirectModel == null && !this.ignoreDefaultModelOnRedirect));
}
...
}

Model modelAvecModelMethodProcessorTraitement:

public class ModelMethodProcessor implements HandlerMethodArgumentResolver, HandlerMethodReturnValueHandler {

@Override
public boolean supportsParameter(MethodParameter parameter) {

return Model.class.isAssignableFrom(parameter.getParameterType());
}
@Override
@Nullable
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {

Assert.state(mavContainer != null, "ModelAndViewContainer is required for model exposure");
return mavContainer.getModel();
}
...
}

return mavContainer.getModel();C'est ça.MapMethodProcessorCohérence

[Impossible de transférer l'image de la chaîne externe,Il peut y avoir un mécanisme antivol à la station source,Il est recommandé de sauvegarder l'image et de la télécharger directement(img-ka2zrYcR-1641479793651)(image/11.jpg)]

Model C'est un autre sens. Map.

Ensuite, regardezMap<String,Object> mapAvecModel model Comment les valeurs fonctionnent request.getAttribute()Acquis.

Tout le monde sait, Toutes les données sont placées dans ModelAndViewContient l'adresse de la page à visiterView,Contient égalementModelDonnées.

Regardez d'abordModelAndView Qu'est - ce qui se passe ensuite? ?

public class DispatcherServlet extends FrameworkServlet {

...
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {

...
try {

ModelAndView mv = null;
...
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
...
}
catch (Exception ex) {

dispatchException = ex;
}
catch (Throwable err) {

// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
//Traitement des résultats de la distribution
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
...
}
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {

...
// Did the handler return a view to render?
if (mv != null && !mv.wasCleared()) {

render(mv, request, response);
...
}
...
}
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {

...
View view;
String viewName = mv.getViewName();
if (viewName != null) {

// We need to resolve the view name.
view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
if (view == null) {

throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
"' in servlet with name '" + getServletName() + "'");
}
}
else {

// No need to lookup: the ModelAndView object contains the actual View object.
view = mv.getView();
if (view == null) {

throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
"View object in servlet with name '" + getServletName() + "'");
}
}
view.render(mv.getModelInternal(), request, response);
...
}
}

InDebugEn mode,view Genre InternalResourceViewCatégorie.

public class InternalResourceView extends AbstractUrlBasedView {

@Override//La méthode est utilisée dansAbstractView,AbstractUrlBasedViewHéritéAbstractView
public void render(@Nullable Map<String, ?> model, HttpServletRequest request,
HttpServletResponse response) throws Exception {

...
Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);
prepareResponse(request, response);
// Voir la prochaine mise en oeuvre de la méthode 
renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
}
@Override
protected void renderMergedOutputModel(
Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {

// Expose the model object as request attributes.
// Exposer le modèle en tant qu'attribut de champ de requête
exposeModelAsRequestAttributes(model, request);//<---Points saillants
// Expose helpers as request attributes, if any.
exposeHelpers(request);
// Determine the path for the request dispatcher.
String dispatcherPath = prepareForRendering(request, response);
// Obtain a RequestDispatcher for the target resource (typically a JSP).
RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath);
...
}
//La méthode est utilisée dansAbstractView,AbstractUrlBasedViewHéritéAbstractView
protected void exposeModelAsRequestAttributes(Map<String, Object> model,
HttpServletRequest request) throws Exception {

model.forEach((name, value) -> {

if (value != null) {

request.setAttribute(name, value);
}
else {

request.removeAttribute(name);
}
});
}
}

exposeModelAsRequestAttributesLa méthode,Map map,Model model Ces deux types de données peuvent donner requestMettre les données dans le champ,Avecrequest.getAttribute()Accès.

2.6 Liaison des paramètres personnalisés EncapsulationPOJO

1)、CAS

index.html: Conversion automatique de type et formatage,Peut être encapsulé en cascade.

<form action="saveUser" method="post">
Nom: <input name="userName"/><br/>
Âge: <input name="age"/><br/>
Anniversaire: <input name="birth"/><br/>
Nom de l'animal de compagnie:<input name="pet.name"/><br/>
Âge des animaux de compagnie:<input name="pet.age"/>
<button type="submit">submit</button>
</form>

Controller:

@RestController
public class ParameterTestController {

/** * Liaison des données: Données de la demande soumises par la page (GET、POST) Peut être lié aux propriétés de l'objet * @param person * @return */
@PostMapping("/saveUser")
public Person saveUser(Person person){

return person;
}
}
@Data
public class Person {

private String userName;
private Integer age;
private Date birth;
private Pet pet;
}
@Data
public class Pet {

private String name;
private String age;
}

Tests:http://localhost:8899 Accès àindex.htmlPage,Remplir les données,Soumettre le formulaire

2)、【Analyse des sources】

Utilisé dans le processus d'emballage ServletModelAttributeMethodProcessor, Ce processeur de paramètres est encapsulé

public class ServletModelAttributeMethodProcessor extends ModelAttributeMethodProcessor {

}
public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResolver, HandlerMethodReturnValueHandler {

//Cette méthodeModelAttributeMethodProcessorCatégorie
@Override
public boolean supportsParameter(MethodParameter parameter) {

return (parameter.hasParameterAnnotation(ModelAttribute.class) ||
(this.annotationNotRequired && !BeanUtils.isSimpleProperty(parameter.getParameterType())));
}
//Cette méthodeModelAttributeMethodProcessorCatégorie
@Override
@Nullable
public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {

...
String name = ModelFactory.getNameForParameter(parameter);
ModelAttribute ann = parameter.getParameterAnnotation(ModelAttribute.class);
if (ann != null) {

mavContainer.setBinding(name, ann.binding());
}
Object attribute = null;
BindingResult bindingResult = null;
if (mavContainer.containsAttribute(name)) {

attribute = mavContainer.getModel().get(name);
}
else {

// Create attribute instance
try {

attribute = createAttribute(name, parameter, binderFactory, webRequest);
}
catch (BindException ex) {

...
}
}
if (bindingResult == null) {

// Bean property binding and validation;
// skipped in case of binding failure on construction.
//============WebDataBinder============
WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);
if (binder.getTarget() != null) {

if (!mavContainer.isBindingDisabled(name)) {

//webData Binder,Lier la valeur du paramètre de requête à la valeur spécifiéeJavaBeanÀ l'intérieur
bindRequestParameters(binder, webRequest);
}
validateIfApplicable(binder, parameter);
if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {

throw new BindException(binder.getBindingResult());
}
}
// Value type adaptation, also covering java.util.Optional
if (!parameter.getParameterType().isInstance(attribute)) {

attribute = binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter);
}
bindingResult = binder.getBindingResult();
}
// Add resolved attribute and BindingResult at the end of the model
Map<String, Object> bindingResultModel = bindingResult.getModel();
mavContainer.removeAttributes(bindingResultModel);
mavContainer.addAllAttributes(bindingResultModel);
return attribute;
}
}

WebDataBinder Utilise ce qu'il y a à l'intérieur Converters Convertir les données demandées en un type de données spécifié,Encore une fois encapsulé dansJavaBeanMoyenne;

En cours de route ,Oui.GenericConversionService:Lors du réglage de chaque valeur,Trouvez tout ce qu'il contientconverterQui peut mettre ce type de données(requestChaîne avec paramètres)Conversion au type spécifié.

3.Moteur de résolution de vue et de modèle

Résolution de la vue:SpringBootNon pris en charge par défaut JSP,Besoin d'introduire la technologie des moteurs de modèles tiers pour réaliser le rendu de page.

3.1 Moteur de modèle-Thymeleaf

1)、thymeleafIntroduction

Thymeleaf is a modern server-side Java template engine for both web and standalone environments, capable of processing HTML, XML, JavaScript, CSS and even plain text.

Thymeleaf C'est un modèle moderne、Côté serveurJavaMoteur de modèle

Site officiel:https://www.thymeleaf.org/

ThymeleafDocuments officiels

https://www.thymeleaf.org/documentation.html

Les moteurs de modèles courants sont: JSP、Velocity、Freemarker、ThymeleafAttendez.,SpringBoot Moteur de modèle linguistique avancé recommandé Thymeleaf( Un modèle moderne JavaMoteur de modèle côté serveur),Syntaxe plus simple,Plus puissant.

[Impossible de transférer l'image de la chaîne externe,Il peut y avoir un mécanisme antivol à la station source,Il est recommandé de sauvegarder l'image et de la télécharger directement(img-l4cjVzbD-1641479793652)(image/image-20210330100319602.png)]

[Impossible de transférer l'image de la chaîne externe,Il peut y avoir un mécanisme antivol à la station source,Il est recommandé de sauvegarder l'image et de la télécharger directement(img-kNQXnZ3h-1641479793652)(image/image-20210330100338657.png)]

2)、Syntaxe de base

1、Expression

https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#standard-expression-syntax

Nom de l'expression Syntaxe Objet
Valeur de la variable ${…} Obtenir le domaine demandé、sessionDomaine、Équivalent objet
Sélectionner une variable *{…} Obtenir la valeur de l'objet contextuel
Message #{…} Obtenir l'équivalent international
Liens @{…} Générer des liens
Expression du fragment ~{…} jsp:include Action,Introduire un fragment de page publique
2、Quantité littérale
Valeur du texte: 'one text' , 'Another one!' ,…
Nombre: 0 , 34 , 3.0 , 12.3 ,…
Booléen: true , false
Valeur nulle: null
Variables: one,two,.... Les variables ne peuvent pas avoir d'espaces
3、Opérations de texte
Assemblage de chaînes: +
Substitution de variables: |The name is ${name}|
4、Opérations mathématiques
Opérateur: + , - , * , / , %
5、Opérations booléennes
Opérateur: and , or
Opération univariée: ! , not
6、Comparer les opérations
Comparaison: > , < , >= , <= ( gt , lt , ge , le )
Équation: == , != ( eq , ne )
7、Opérations conditionnelles
If-then: (if) ? (then)
If-then-else: (if) ? (then) : (else)
Default: (value) ?: (defaultvalue)
8、Opérations spéciales
Aucune opération: _

3)、Définir les valeurs des attributs th:attr

Définir une valeur unique

<form action="subscribe.html" th:attr="[email protected]{/subscribe}">
<fieldset>
<input type="text" name="email" />
<input type="submit" value="Subscribe!" th:attr="value=#{subscribe.submit}"/>
</fieldset>
</form>

Définir plusieurs valeurs

<img src="../../images/gtvglogo.png" th:attr="[email protected]{/images/gtvglogo.png},title=#{logo},alt=#{logo}" />

Au lieu d'écrire les deux ci - dessus th:xxxx

<input type="submit" value="Subscribe!" th:value="#{subscribe.submit}"/>
<form action="subscribe.html" th:action="@{/subscribe}">

Tous lesh5écriture d'étiquettes compatible

https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#setting-value-to-specific-attributes

Simple expressions:(Syntaxe d'expression)
1.Variable Expressions: ${...}: Obtenir la valeur de la variable OGNL
1)、Obtenir les propriétés de l'objet、Méthode d'appel OGNL expressions
2)、Utiliser des objets de base intégrés Expression Basic Objects
#ctx : the context object. Objet contextuel actuel
#vars: the context variables. Valeur de la variable dans le contexte actuel
#locale : the context locale.Informations régionales
WebObjet de base de:
#request : (only in Web Contexts) the HttpServletRequest object.
#response : (only in Web Contexts) the HttpServletResponse object.
#session : (only in Web Contexts) the HttpSession object.
#servletContext : (only in Web Contexts) the ServletContext object.
AnnexeAppendix A Utilisation dans :Par exemple${session.foo} Obtenir à partir du domaine de demande fooValeur de
3)、Quelques objets d'outils intégrés Expression Utility Objects
#execInfo : information about the template being processed.
#dates : methods for java.util.Date objects: formatting, component extraction, etc.
#calendars : analogous to #dates , but for java.util.Calendar objects.
#numbers : methods for formatting numeric objects.
#strings : methods for String objects: contains, startsWith, prepending/appending, etc.
#objects : methods for objects in general.
#bools : methods for boolean evaluation.
#arrays : methods for arrays.
#lists : methods for lists.
AnnexeAppendix B Utilisation dans
2.Selection Variable Expressions: *{...} :Choisissez une expression
Sélectionnez les expressions et ${...}C'est la même fonctionnalité, Mais il peut être complété th:object="${session.user}Utilisation
<div th:object="${session.user}">
Avecth:object Dans une session de stockage userValeur de,En ce moment* Représente directement cet objet ,Utilisation directe*{ Propriétés de l'objet }
<p>Name: <span th:text="*{firstName}">Sebastian</span>.</p>
<p>Surname: <span th:text="*{lastName}">Pepper</span>.</p>
<p>Nationality: <span th:text="*{nationality}">Saturn</span>.</p>
</div>
3.Message Expressions: #{...}:Accès au contenu international
4.Link URL Expressions: @{...}:DéfinitionURL
<!-- 'http://localhost:8080/gtvg/order/details?orderId=3 ' -->
<a href="details.html" En ce moment / Représente directement le projet en cours , Évitez d'écrire sur l'ordinateur central ip Et le numéro de port et le nom du projet
th:href="@{ /order/details( orderId=${o.id} , orderType=${o.type} ) }">view</a>
5.Fragment Expressions: ~{...}:Expression de référence du fragment
<div th:insert="~{commons :: main}">...</div>

4)、Itération th:each

<tr th:each="prod : ${prods}">
<td th:text="${prod.name}">Onions</td>
<td th:text="${prod.price}">2.41</td>
<td th:text="${prod.inStock}? #{true} : #{false}">yes</td>
</tr>
<tr th:each="prod,iterStat : ${prods}" th:class="${iterStat.odd}? 'odd'">
<td th:text="${prod.name}">Onions</td>
<td th:text="${prod.price}">2.41</td>
<td th:text="${prod.inStock}? #{true} : #{false}">yes</td>
</tr>

5)、Opérations conditionnelles th:if

<a href="comments.html" th:href="@{/product/comments(prodId=${prod.id})}" th:if="${not #lists.isEmpty(prod.comments)}">view</a>
<div th:switch="${user.role}">
<p th:case="'admin'">User is an administrator</p>
<p th:case="#{roles.manager}">User is a manager</p>
<p th:case="*">User is some other thing</p>
</div>

6)、Priorité de l'attribut

[Impossible de transférer l'image de la chaîne externe,Il peut y avoir un mécanisme antivol à la station source,Il est recommandé de sauvegarder l'image et de la télécharger directement(img-NNU0YUz7-1641479793653)(image/image-20210330101129143.png)]

3.2 thymeleafUtiliser

1)、IntroductionStarterDémarreur

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

2)、Configuré automatiquementthymeleaf

Inspring-boot-autoconfigureDejarSous le sac.,FourniThymeleafClasse de configuration automatique pour

@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(ThymeleafProperties.class)
@ConditionalOnClass({
 TemplateMode.class, SpringTemplateEngine.class })
@AutoConfigureAfter({
 WebMvcAutoConfiguration.class, WebFluxAutoConfiguration.class })
//ThymeleafClasse de configuration automatique pour
public class ThymeleafAutoConfiguration {

}

Inspring-boot-autoconfigureDejarSous le sac.,FournithymeleafRègles par défaut pour

//DéfiniThymeleaf Règles par défaut utilisées 
@ConfigurationProperties( prefix = "spring.thymeleaf" )
public class ThymeleafProperties {

private static final Charset DEFAULT_ENCODING = StandardCharsets.UTF_8;
// Préfixe par défaut 
public static final String DEFAULT_PREFIX = "classpath:/templates/";
// Suffixe par défaut 
public static final String DEFAULT_SUFFIX = ".html";
}

Stratégie auto - configurée

  • 1、Tous lesthymeleafToutes les valeurs de configuration pour ThymeleafProperties
  • 2、Configuré SpringTemplateEngine
  • 3、Configuré ThymeleafViewResolver
  • 4、Nous avons juste besoin de développer la page directement
// Emplacement du modèle de page 
public static final String DEFAULT_PREFIX = "classpath:/templates/"
// Nom du suffixe du fichier
public static final String DEFAULT_SUFFIX = ".html" //xxx.html

3)、Développement de pages

Première étape:ImporterThymeleafEspace de noms pour

Les espaces de noms suivants doivent être ajoutés à la page , Utilisé dans la page thymeleaf Il y aura un indice

<html lang="en" xmlns:th="http://www.thymeleaf.org">
Deuxième étape:Écrire le niveau de contrôle
@Controller
public class ViewTestController {

@GetMapping("/hello")
public String hello(Model model){

//modelLes données sont placées dans le champ de demande
model.addAttribute("msg","Développer vigoureusement la culture industrielle");
model.addAttribute("link","http://www.baidu.com");
return "success";
}
}
Troisième étape:UtiliserThymeleafSyntaxe

Page /templates/success.html

<!DOCTYPE html>
<!-- ImporterThymeleafEspace de noms pour, Peut avoir des conseils -->
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!-- th:text Oui.h1 Le contenu du texte dans l'étiquette est défini aux données d'arrière - plan spécifiées -->
<!-- th:text Afficher le texte dans l'étiquette ,Sortie telle quelle,Ne pas s'échapperhtmlCode,Similaire àjQueryDanstext -->
<!-- th:utext Afficher le texte dans l'étiquette ,Va s'échapperhtmlCode, Peut afficher le style spécifié ,Similaire àjQueryDanshtml -->
<h1 th:text="${msg}">Ha Ha!</h1>
<h2>
<a href="www.baidu.com" th:href="@{${link}}">À Baidu1</a>
<br/>
<a href="www.baidu.com" th:href="@{/link}">À Baidu2</a>
</h2>
</body>
</html>
# Définir le nom de l'application 
server:
servlet:
context-path: /app
# Après ce réglage ,URLÀ insérer/app, Par exemple:http://localhost:8080/app/hello.html

3.3 CAS-Construire un système de gestion de fond

1)、Création de projets

UtiliserIDEADeSpring Initializr. Cochez l'initiateur :thymeleaf、web-starter、devtools、lombok.

2)、Traitement statique des ressources

Auto - configuré,Il suffit de mettre toutes les ressources statiques dans static Sous le dossier.

/static Placement css,jsRessources isostatiques

/templates/login.html Page de connexion

3)、Construction du chemin

th:action="@{/login}"

<html lang="en" xmlns:th="http://www.thymeleaf.org">
<form class="form-signin" method="post" th:action="@{/login}">
<!-- Rappel du message -->
<label style="color: red" th:text="${msg}"></label>
<input type="text" name="userName" class="form-control" placeholder="User ID" autofocus>
<input type="password" name="password" class="form-control" placeholder="Password">
<button class="btn btn-lg btn-login btn-block" type="submit">
<i class="fa fa-check"></i>
</button>
</form>

5)、Saut de page

@Controller
public class IndexController {

//Aller à la page de connexion
@GetMapping(value = {
"/","/login"})
public String gotoLogin(){

//classpath:/templates/login.html
return "login";
}
//Fonctions de connexion
@PostMapping(value = "/login")
public String login(User user, HttpSession session ,Model model){

if(StringUtils.hasLength(user.getName()) && StringUtils.hasLength(user.getEmail()) && "[email protected]".equals(user.getEmail()) ){

session.setAttribute("user",user);
return "redirect:main";
}else{

model.addAttribute("msg"," Le compte ne correspond pas à la boîte aux lettres !");
return "login";
}
}
//Aller à la page d'accueil
@GetMapping("/main")
public String gotoMain(HttpSession session , Model model){

Object user = session.getAttribute("user");
if(user ==null){

//Non connecté
model.addAttribute("msg","Connectez - vous d'abord,Re - visit!");
return "login";
}else{

//Connecté,Sautez à la page principalemain.html
return "main";
}
}
//Déconnecter
@GetMapping("/logout")
public String logout(HttpSession session , Model model){

session.invalidate();
model.addAttribute("msg"," Déconnecté !");
return "redirect:login";
}
}

6)、main.html Page d'accueil

thymeleafEn ligne https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#inlining

Afficher les informations du connecteur

<p>Hello, [[${session.user.name}]]</p>

Déconnecter

<li><a th:href="@{/logout}"><i class="fa fa-sign-out"></i> Log Out</a></li>

7)、Modèle

@AllArgsConstructor
@NoArgsConstructor
@Data
public class User {

private String userName;
private String password;
}

3.4 CAS–Extraire les pages publiques

Template Layout https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#template-layout

<!-- In /templates/footer.html Partie publique de -->
<foot th:fragment="copy" id="data">
&copy; 2011 The Good Thymes Virtual Grocery
</foot>
<!-- Trois façons d'introduire Template Engine name :: Nom du fragment -->
<body>
<!-- Insérer -->
<div th:insert="footer :: copy"></div>
<!-- Remplacer -->
<div th:replace="footer :: #data"></div>
<!-- Contient -->
<div th:include="footer :: copy"></div>
</body>
<!-- Résultats -->
<body>
<div>
<foot>
&copy; 2011 The Good Thymes Virtual Grocery
</foot>
</div>
<foot>
&copy; 2011 The Good Thymes Virtual Grocery
</foot>
<div>
&copy; 2011 The Good Thymes Virtual Grocery
</div>
</body>

Pages publiques

  • /templates/common.html
<!DOCTYPE html>
<!--Note to addxmlns:thPour ajouterthymeleafÉtiquette de-->
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<!-- Tête commune -->
<head th:fragment="commonheader">
<!--common-->
<link href="css/style.css" th:href="@{/css/style.css}" rel="stylesheet">
<link href="css/style-responsive.css" th:href="@{/css/style-responsive.css}" rel="stylesheet">
...
</head>
<body>
<!-- Barre de navigation commune à gauche left side start-->
<div id="leftmenu" class="left-side sticky-left-side">
...
<div class="left-side-inner">
...
<!--sidebar nav start-->
<ul class="nav nav-pills nav-stacked custom-nav">
<li><a th:href="@{/main.html}"><i class="fa fa-home"></i> <span>Dashboard</span></a></li>
...
<li class="menu-list nav-active"><a href="#"><i class="fa fa-th-list"></i> <span>Data Tables</span></a>
<ul class="sub-menu-list">
<li><a th:href="@{/basic_table}"> Basic Table</a></li>
<li><a th:href="@{/dynamic_table}"> Advanced Table</a></li>
<li><a th:href="@{/responsive_table}"> Responsive Table</a></li>
<li><a th:href="@{/editable_table}"> Edit Table</a></li>
</ul>
</li>
...
</ul>
<!--sidebar nav end-->
</div>
</div>
<!-- left side end-->
<!-- Barre de menu en - tête commune header section start-->
<div th:fragment="headermenu" class="header-section">
<!--toggle button start-->
<a class="toggle-btn"><i class="fa fa-bars"></i></a>
<!--toggle button end-->
...
</div>
<!-- header section end-->
<!-- Script public -->
<div id="commonscript">
<!-- Placed js at the end of the document so the pages load faster -->
<script th:src="@{/js/jquery-1.10.2.min.js}"></script>
<script th:src="@{/js/jquery-ui-1.9.2.custom.min.js}"></script>
<script th:src="@{/js/jquery-migrate-1.2.1.min.js}"></script>
<script th:src="@{/js/bootstrap.min.js}"></script>
<script th:src="@{/js/modernizr.min.js}"></script>
<script th:src="@{/js/jquery.nicescroll.js}"></script>
<!--common scripts for all pages-->
<script th:src="@{/js/scripts.js}"></script>
</div>
</body>
</html>
  • /templates/table/basic_table.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
<meta name="description" content="">
<meta name="author" content="ThemeBucket">
<link rel="shortcut icon" href="#" type="image/png">
<title>Basic Table</title>
<!-- Oui.common.htmlUn fragment de code de Inclus-->
<div th:include="common :: commonheader"> </div>
</head>
<body class="sticky-header">
<section>
<!-- Oui.common.htmlUn fragment de code de Remplacer par-->
<div th:replace="common :: #leftmenu"></div>
<!-- main content start-->
<div class="main-content" >
<!-- Oui.common.htmlUn fragment de code de Remplacer par-->
<div th:replace="common :: headermenu"></div>
...
</div>
<!-- main content end-->
</section>
<!-- Oui.common.htmlUn fragment de code de Inclus-->
<!-- Placed js at the end of the document so the pages load faster -->
<div th:include="common :: #commonscript"></div>
</body>
</html>

3.5 CAS- Traverser les données et le rendu de page

https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#iteration

Code de la couche de contrôle

@GetMapping("/dynamic_table")
public String dynamic_table(Model model){

//Traversée du contenu du tableau
List<User> users
= Arrays.asList(new User("zhangsan", "123456"),
new User("lisi", "123444"),
new User("haha", "aaaaa"),
new User("hehe ", "aaddd"));
model.addAttribute("users",users);
return "table/dynamic_table";
}

Code de la page

<!-- PlusthymeleafJe peux l'utiliser. -->
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<table class="display table table-bordered" id="hidden-table-info">
<thead>
<tr>
<th>#</th>
<th>Nom d'utilisateur</th>
<th>Mot de passe</th>
</tr>
</thead>
<tbody>
<tr class="gradeX" th:each="user,stats:${users}">
<td th:text="${stats.count}">Trident</td>
<td th:text="${user.userName}">Internet</td>
<td >[[${user.password}]]</td>
</tr>
</tbody>
</table>

3.6 【Analyse des sources】Résolution de la vue

Processus de principe

1、Dans le processus de traitement de la méthode objective,Toutes les données sont placées dans ModelAndViewContainer À l'intérieur.Inclure les adresses des données et des vues

2、Le paramètre de la méthode est un objet de type personnalisé(Déterminé à partir des paramètres de la demande),Reposez - le surModelAndViewContainer

3、Une fois l'exécution de n'importe quelle méthode cible terminée ModelAndView(Adresses des données et des vues).

4、processDispatchResult Traitement des résultats de la distribution(Comment le changement de page répond)

  • render(mv, request, response); Faire la logique de rendu de page

    • Selon la méthodeStringRetour à View Objet【Définit la logique de rendu de la page】
      • 1、Toutes les tentatives de l'analyseur de vue sont basées sur la valeur de retour actuelle àViewObjet getBeanView()
      • 2、Je l'ai. redirect:/main.html --> Thymeleaf new RedirectView()
      • 3、ContentNegotiationViewResolver Il contient tous les Analyseurs de vue ci - dessous,En interne, vous pouvez également utiliser tous les Analyseurs de vue ci - dessous pour obtenir l'objet de vue.View
      • 4、view.render(mv.getModelInternal(), request, response); Objet de vue appelé personnalisérenderEffectuer des travaux de rendu de page
    • 5、renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
    • RedirectView Comment rendre【Rediriger vers une page】
      • 1、Obtenir la cibleurlAdresse
      • 2、response.sendRedirect(encodedURL);

Résolution de la vue:

  • Renvoie la valeur à forward: C'est parti.: new InternalResourceView(forwardUrl); --> Demande de transmissionrequest.getRequestDispatcher(path).forward(request, response);

  • Renvoie la valeur à redirect: C'est parti.: new RedirectView() --> Redirection de la réponse

response.sendRedirect(path);

  • La valeur de retour est une chaîne normale: new ThymeleafView()—>

[Impossible de transférer l'image de la chaîne externe,Il peut y avoir un mécanisme antivol à la station source,Il est recommandé de sauvegarder l'image et de la télécharger directement(img-wFbtT1Z4-1641479793653)(image/19.jpg)]

[Impossible de transférer l'image de la chaîne externe,Il peut y avoir un mécanisme antivol à la station source,Il est recommandé de sauvegarder l'image et de la télécharger directement(img-fE345oxV-1641479793654)(image/20.jpg)]

[Impossible de transférer l'image de la chaîne externe,Il peut y avoir un mécanisme antivol à la station source,Il est recommandé de sauvegarder l'image et de la télécharger directement(img-RnNgl4Uk-1641479793654)(image/21.jpg)]

5.Intercepteur

5.1 HandlerInterceptor Interface

/** * Vérification de connexion * 1、Configurer les requêtes à intercepter par l'intercepteur * 2、Placer ces configurations dans un conteneur */
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {

/** * Avant la mise en œuvre de la méthode cible * @param request * @param response * @param handler * @return * @throws Exception */
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

String requestURI = request.getRequestURI();
log.info("preHandleLe chemin de demande intercepté est{}",requestURI);
//Login check Logic
HttpSession session = request.getSession();
Object loginUser = session.getAttribute("loginUser");
if(loginUser != null){

//Release
return true;
}
//Arrêtez!.Non connecté.Aller à la page d'atterrissage
request.setAttribute("msg","Veuillez vous connecter.");
request.getRequestDispatcher("/").forward(request,response);
return false;
}
/** * Une fois la mise en œuvre de la méthode cible terminée * @param request * @param response * @param handler * @param modelAndView * @throws Exception */
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

log.info("postHandleMise en œuvre{}",modelAndView);
}
/** * Après le rendu de la page * @param request * @param response * @param handler * @param ex * @throws Exception */
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

log.info("afterCompletionException à l'exécution{}",ex);
}
}

5.2 Configurer l'intercepteur

/** * 1、Écrivez une implémentation d'intercepteurHandlerInterceptorInterface * 2、L'intercepteur est enregistré dans le conteneur(RéalisationWebMvcConfigurerDeaddInterceptors) * 3、Spécifier les règles d'interception【Si vous interceptez tout,Les ressources statiques sont également interceptées】 */
@Configuration
public class MyWebConfig implements WebMvcConfigurer {

@Override
public void addInterceptors(InterceptorRegistry registry) {

registry.addInterceptor(new LoginInterceptor())
.addPathPatterns("/**") //Toutes les demandes ont été interceptées, y compris les ressources statiques
.excludePathPatterns("/","/login","/css/**","/fonts/**","/images/**","/js/**"); // Définir la demande de mainlevée 
}
}

5.3 【Analyse des sources】Principe de l'intercepteur

1、Selon la demande actuelle,Trouver**HandlerExecutionChain【**Peut traiter la demandehandlerEthandlerTous les intercepteurs de】

2、D'abord.Exécution séquentielle Tous les intercepteurs preHandleMéthodes

  • 1、Si l'intercepteur actuelpreHandleRetour àtrue.Pour exécuter le prochain intercepteurpreHandle
  • 2、Si l'intercepteur actuel retourne commefalse.Directement inversé pour exécuter tous les intercepteurs qui ont été exécutés afterCompletion;

3、Si l'un des intercepteurs revientfalse.Sauter directement sans exécuter la méthode cible

4、Tous les intercepteurs sont retournésTrue.Mise en œuvre de l'approche ciblée

5、L'ordre inverse exécute tous les intercepteurspostHandleMéthodes.

6、Toute exception aux étapes précédentes déclenchera directement l'ordre inverse afterCompletion

7、Une fois la page rendue avec succès,Ça déclenche aussi l'ordre inverse afterCompletion

[Impossible de transférer l'image de la chaîne externe,Il peut y avoir un mécanisme antivol à la station source,Il est recommandé de sauvegarder l'image et de la télécharger directement(img-qvlWubyM-1641479793655)(image/23.jpg)]

6.Téléchargement de fichiers

6.1 Formulaire de page

Utiliser le form_layouts.htmlPage

<form method="post" action="/upload" enctype="multipart/form-data">
<input type="file" name="file"><br>
<input type="submit" value="Soumettre">
</form>

6.2 Code de téléchargement de fichiers

/** * MultipartFile Encapsulation automatique des fichiers téléchargés * @param email * @param username * @param headerImg * @param photos * @return */
@PostMapping("/upload")
public String upload(@RequestParam("email") String email,
@RequestParam("username") String username,
@RequestPart("headerImg") MultipartFile headerImg,
@RequestPart("photos") MultipartFile[] photos) throws IOException {

log.info("Informations téléchargées:email={},username={},headerImg={},photos={}",
email,username,headerImg.getSize(),photos.length);
if(!headerImg.isEmpty()){

//Enregistrer sur le serveur de fichiers,OSSServeur
String originalFilename = headerImg.getOriginalFilename();
headerImg.transferTo(new File("H:\\cache\\"+originalFilename));
}
if(photos.length > 0){

for (MultipartFile photo : photos) {

if(!photo.isEmpty()){

String originalFilename = photo.getOriginalFilename();
photo.transferTo(new File("H:\\cache\\"+originalFilename));
}
}
}
return "main";
}

6.3 【Analyse des sources】Principe de configuration automatique

**Classe de configuration automatique de téléchargement de fichiers-MultipartAutoConfiguration-**MultipartProperties

  • Configuré automatiquement StandardServletMultipartResolver 【Analyseur de téléchargement de fichiers】

  • Étapes de principe

    • 1、Demande d'utilisation de l'analyseur de téléchargement de fichiers pour juger(isMultipart)Et emballer(resolveMultipart,RetourMultipartHttpServletRequest)Demande de téléchargement de fichiers
  • 2、L'analyseur de paramètres pour analyser le contenu du fichier dans la requête est enveloppé dansMultipartFile

  • **3、Oui.requestLes informations du fichier sont encapsulées dans unMap;**MultiValueMap<String, MultipartFile>

FileCopyUtils.Implémenter une copie du flux de fichiers

@PostMapping("/upload")
public String upload(@RequestParam("email") String email,
@RequestParam("username") String username,
@RequestPart("headerImg") MultipartFile headerImg,
@RequestPart("photos") MultipartFile[] photos)

[Impossible de transférer l'image de la chaîne externe,Il peut y avoir un mécanisme antivol à la station source,Il est recommandé de sauvegarder l'image et de la télécharger directement(img-uNoa5UwZ-1641479793655)(image/24.jpg)]

7.Gestion des exceptions

https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-error-handling

7.1 Règle par défaut

1.Par défaut,Spring BootOffre/errorTraiter toutes les cartes erronées.

2.PourClient machine,Il va générerJSONRéponse,Contient des erreurs,HTTPDétails des messages d'état et d'exception;

[Impossible de transférer l'image de la chaîne externe,Il peut y avoir un mécanisme antivol à la station source,Il est recommandé de sauvegarder l'image et de la télécharger directement(img-6T6cihVn-1641479793655)(image/25.jpg)]

PourClient du Navigateur,Répondre à un“ whitelabel”Vue des erreurs,ParHTMLLe format présente les mêmes données.

[Impossible de transférer l'image de la chaîne externe,Il peut y avoir un mécanisme antivol à la station source,Il est recommandé de sauvegarder l'image et de la télécharger directement(img-1BfdFFla-1641479793656)(image/26.jpg)]

3.Pour le personnaliser,AjouterView La vue se résout à error.

4.Pour remplacer complètement le comportement par défaut,Peut être réalisé ErrorControllerEt enregistrer ce typeBeanDéfinition,Ou ajouterErrorAttributesComposants de type Remplacer son contenu par un mécanisme existant .

5.error/En bas4xx,5xxLa page est automatiquement résolue.

[Impossible de transférer l'image de la chaîne externe,Il peut y avoir un mécanisme antivol à la station source,Il est recommandé de sauvegarder l'image et de la télécharger directement(img-9uhdhF59-1641479793656)(image/1606024592756-d4ab8a6b-ec37-426b-8b39-010463603d57.png)]

7.2 Personnaliser la logique de gestion des erreurs

1)、Page d'erreur personnalisée

error/404.html error/5xx.html

La page avec le Code d'état d'erreur exact correspond exactement,Non, je cherche 4xx.html;Si ce n'est pas le cas, déclenchez la page blanche;

Point de déclenchement:

@Controller
public class TableController {

//Déclencheur400 Bad Request
@GetMapping("/basic_table")
public String basic_table(Model model, @RequestParam("a")int a){

//Données analogiques
List<User> users
= Arrays.asList(new User("zhangsan", "123456"),
new User("lisi", "123444"),
new User("haha", "aaaaa"),
new User("hehe ", "aaddd"));
model.addAttribute("users",users);
return "table/basic_table";
}
}

2)、@[email protected] exception Processor

Au rez - de - chaussée, ExceptionHandlerExceptionResolver Soutien

@Slf4j
@ControllerAdvice // Contrôleur amélioré 
public class GlobalExceptionhandler {

// Définir un traitement spécifique "Anomalie mathématique"Processeur pour
@ExceptionHandler({
ArithmeticException.class})
public String handlerArithException(Exception e){

log.error("Anomalie:{}",e.getMessage());
return "login";
}
}

Point de déclenchement:

@Controller
public class TableController {

@GetMapping("/basic_table")
public String basic_table(Model model){

//Données analogiques
List<User> users
= Arrays.asList(new User("zhangsan", "123456"),
new User("lisi", "123444"),
new User("haha", "aaaaa"),
new User("hehe ", "aaddd"));
// Déclenche une exception mathématique 
int i = 10/0;
model.addAttribute("users",users);
return "table/basic_table";
}
}

3)、@ResponseStatus+Exception personnalisée

Au rez - de - chaussée, **ResponseStatusExceptionResolverSoutien **

Prends ça.responsestatusInformations annotées appel sous - jacent response.sendError(statusCode, resolvedReason);

tomcatEnvoyé par/error

//Exception personnalisée Code d'état d'erreur de réponse de liaison 
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
public class CustomException extends RuntimeException {

public CustomException() {

super();
}
public CustomException(String message) {

super(message);
}
}

Point de déclenchement:

@Controller
public class TableController {

@GetMapping("/basic_table")
public String basic_table(Model model){

//Données analogiques
List<User> users
= Arrays.asList(new User("zhangsan", "123456"),
new User("lisi", "123444"),
new User("haha", "aaaaa"),
new User("hehe ", "aaddd"));
// Déclenche une exception personnalisée 
if(users.size()>3){

throw new CustomException(" Trop de valeur ");
}
model.addAttribute("users",users);
return "table/basic_table";
}
}

4)、SpringException au rez - de - chaussée, Par exemple, la conversion de type de paramètre est anormale

Au rez - de - chaussée,DefaultHandlerExceptionResolverSoutien,Gérer les exceptions au bas du cadre(Par exemple:400 Paramètre de requête manquant )

response.sendError(HttpServletResponse.SC_BAD_REQUEST, ex.getMessage());

Cette demande prend fin immédiatement ,tomcatEnvoyé par/error,ParBasicErrorControllerTraitement du Contrôleur.

tomcat Page d'erreur native :

[Impossible de transférer l'image de la chaîne externe,Il peut y avoir un mécanisme antivol à la station source,Il est recommandé de sauvegarder l'image et de la télécharger directement(img-7K32hBaB-1641479793657)(image/27.jpg)]

5)、Mise en œuvre personnalisée HandlerExceptionResolver Gestion des exceptions

Peut être utilisé comme règle de gestion des exceptions globales par défaut

[Impossible de transférer l'image de la chaîne externe,Il peut y avoir un mécanisme antivol à la station source,Il est recommandé de sauvegarder l'image et de la télécharger directement(img-qHAxu7iE-1641479793657)(image/1606114688649-e6502134-88b3-48db-a463-04c23eddedc7.png)]

//Définir les priorités,Plus le nombre est petit, plus la priorité est élevée
@Order(value = Ordered.HIGHEST_PRECEDENCE)
@Component
public class CustomHandlerExceptionResolver implements HandlerExceptionResolver {

@Override
public ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) {

try {

response.sendError(422," Erreur personnalisée ");
} catch (IOException e) {

e.printStackTrace();
}
return new ModelAndView();
}
}

6)、ErrorViewResolver Mise en œuvre de l'exception de gestion personnalisée

1.Il suffit d'exécuterresponse.sendError() ,errorLa demande sera transmise àcontroller;

2. Il y a des anomalies que personne ne peut gérer ,tomcatLe rez - de - chaussée aussi response.sendError(),errorLa demande sera transmise àcontroller;

3.BasicErrorController L'adresse de la page à sauter est ErrorViewResolver L'analyseur de vue analyse ;

7.3 【Analyse des sources】Gestion des exceptions principe de configuration automatique

  • ErrorMvcAutoConfiguration Configurer automatiquement les règles de gestion des exceptions

    • Composants dans le conteneur:Type:DefaultErrorAttributes -> id:errorAttributes
      • public class DefaultErrorAttributes implements ErrorAttributes, HandlerExceptionResolver
      • DefaultErrorAttributes:Définir les données qui peuvent être incluses dans la page d'erreur.

[Impossible de transférer l'image de la chaîne externe,Il peut y avoir un mécanisme antivol à la station source,Il est recommandé de sauvegarder l'image et de la télécharger directement(img-NZHtnqhW-1641479793658)(image/28.jpg)]

[Impossible de transférer l'image de la chaîne externe,Il peut y avoir un mécanisme antivol à la station source,Il est recommandé de sauvegarder l'image et de la télécharger directement(img-ZyW0QDRS-1641479793658)(image/30.jpg)]

    • **Composants dans le conteneur:Type:**BasicErrorController --> id:basicErrorController(json+Page blanche Réponse adaptée)
      • Traitement par défaut /error Demande de chemin;Réponse de la page new ModelAndView(“error”, model);
      • Il y a des composants dans le conteneur View->id- Oui.error;(Répondre à la page d'erreur par défaut)
      • Assemblage dans un conteneur BeanNameViewResolver(Voir l'analyseur);Comme composant par le nom de vue retournéidVa chercher dans le conteneurViewObjet.
    • **Composants dans le conteneur:**Type:**DefaultErrorViewResolver -> id:**conventionErrorViewResolver
      • En cas d'erreur,Oui.HTTPCode d'état pour Comme adresse de la page de vue(viewName),Trouver la vraie Page
      • error/404、5xx.html

Si vous voulez retourner à la page;Je vais chercher.errorVoir【StaticView】.(La valeur par défaut est une page blanche)

[Impossible de transférer l'image de la chaîne externe,Il peut y avoir un mécanisme antivol à la station source,Il est recommandé de sauvegarder l'image et de la télécharger directement(img-rHAn2gSQ-1641479793659)(image/29.jpg)]

7.4 【Analyse des sources】Procédure de traitement des exceptions

1、Mise en œuvre de l'approche ciblée,Toute exception pendant l'exécution de la méthode cible seracatch、Et marque la fin de la demande actuelle;Et avec dispatchException

2、Aller au processus de résolution de la vue(Rendu de page)

processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

3、mv = processHandlerException;TraitementhandlerException survenue,Traitement terminé retourModelAndView;

  • 1、Traverser tout **handlerExceptionResolvers,Voir qui peut gérer l'exception actuelle【**HandlerExceptionResolverAnalyseur d'exception du processeur】

[Impossible de transférer l'image de la chaîne externe,Il peut y avoir un mécanisme antivol à la station source,Il est recommandé de sauvegarder l'image et de la télécharger directement(img-C5Y9CsmN-1641479793659)(image/31.jpg)]

  • -2、Système par défaut Analyseur d'exception;

[Impossible de transférer l'image de la chaîne externe,Il peut y avoir un mécanisme antivol à la station source,Il est recommandé de sauvegarder l'image et de la télécharger directement(img-BXuCwLix-1641479793660)(image/1606047109161-c68a46c1-202a-4db1-bbeb-23fcae49bbe9.png)]

    • 1、DefaultErrorAttributesTraiter l'exception en premier.Enregistrer les informations d'exception dansrrequestDomaine,Et revenirnull;
    • 2、Par défaut, personne ne peut gérer l'exception,Donc l'exception est lancée
      • 1、S'il n'y a personne qui puisse gérer le dernier étage, il sera envoyé. /error Demande.Il sera en basBasicErrorControllerTraitement
      • 2、Résoudre la vue des erreurs;Traverser tout ErrorViewResolver Voir qui peut analyser.
    • [Impossible de transférer l'image de la chaîne externe,Il peut y avoir un mécanisme antivol à la station source,Il est recommandé de sauvegarder l'image et de la télécharger directement(img-xfxaONeC-1641479793660)(image/1606047900473-e31c1dc3-7a5f-4f70-97de-5203429781fa.png)]

      • 3、Par défaut DefaultErrorViewResolver ,Le but est d'utiliser le Code d'état de réponse comme adresse de la page d'erreur,error/500.html
      • 4、Le moteur Template répond enfin à cette page error/500.html

8.WebInjection de composants natifs(Servlet、Filter、Listener)

Site officiel: Prise en charge des conteneurs intégrés

https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-embedded-container

8.1 UtiliserServlet API

Les méthodes suivantes sont recommandées

// Dans la classe de configuration principale , Utilisez les annotations pour spécifier le scan ServletLe sac de,Spécifiez NativeServletLes composants sont là
@ServletComponentScan(basePackages = "com.igeek")
//Sur mesureServletMoyenne,Héritage requisHttpServlet,Et basé surServlet3.0 Les identificateurs d'annotation utilisés sont pris en charge après 
@WebServlet(urlPatterns = "/my") //Effets:Réponse directe,Pas passé.SpringIntercepteur pour
//Filtres personnalisés
@WebFilter(urlPatterns={
"/css/*","/images/*"})
//Moniteur personnalisé
@WebListener

8.2 UtiliserRegistrationBean

ServletRegistrationBean, FilterRegistrationBean, and ServletListenerRegistrationBean

@Configuration
public class MyRegistConfig {

@Bean
public ServletRegistrationBean myServlet(){

MyServlet myServlet = new MyServlet();
return new ServletRegistrationBean(myServlet,"/my","/my02");
}
@Bean
public FilterRegistrationBean myFilter(){

MyFilter myFilter = new MyFilter();
//return new FilterRegistrationBean(myFilter,myServlet());
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(myFilter);
filterRegistrationBean.setUrlPatterns(Arrays.asList("/my","/css/*"));
return filterRegistrationBean;
}
@Bean
public ServletListenerRegistrationBean myListener(){

MySwervletContextListener mySwervletContextListener = new MySwervletContextListener();
return new ServletListenerRegistrationBean(mySwervletContextListener);
}
}

8.3 【Analyse des sources】DispatchServlet Comment s'inscrire

Extension:DispatchServlet Comment s'inscrire?

  • Automatiquement configuré dans le conteneur DispatcherServlet Propriété liée à WebMvcProperties;L'entrée de profil correspondante est spring.mvc.
  • Adoption ServletRegistrationBean<DispatcherServlet> Prends ça. DispatcherServlet Configurer pour entrer.
  • La cartographie par défaut est / Chemin.

Tomcat-ServletPrincipes de traitement:

PlusieursServlet Quand ils peuvent tous travailler sur le même chemin de couche , Le principe de l'optimisation précise , Pour correspondre à l'exécution .

9.Principe de personnalisation

9.1 Les façons courantes de personnaliser

Mode 1:Modifier le profil

Mode 2:XxxCustomizer Personnalisateur

Mode 3:Écrire des classes de configuration personnalisées xxxConfiguration + @BeanRemplacer、Ajouter un composant par défaut dans le conteneur、Voir l'analyseur

WebApplication Écrivez une implémentation de classe de configuration WebMvcConfigurer Peut être personnaliséwebFonction;+ @BeanÉtendre un peu plus de composants dans le conteneur

@Configuration
public class MyWebConfig implements WebMvcConfigurer
  • @EnableWebMvc + WebMvcConfigurer ——> @Bean Peut prendre le contrôle completSpringMVC,Toutes les règles sont reconfigurées par elles - mêmes; Réaliser des fonctions personnalisées et étendues

    • Principes
    • 1、WebMvcAutoConfiguration Par défautSpringMVCClasse de fonctions de configuration automatique pour.Ressources statiques、Page de bienvenue…
    • 2、Une fois utilisé @EnableWebMvc Les notes @Import(DelegatingWebMvcConfiguration.class)
    • 3、DelegatingWebMvcConfiguration Le rôle de,C'est promisSpringMVC Fonctions d'utilisation de base
      • Mettez tous les systèmes WebMvcConfigurer Prends ça..La personnalisation de toutes les fonctions WebMvcConfigurer Ça marche ensemble
      • Certains composants très bas sont automatiquement configurés.RequestMappingHandlerMapping Les composants dont dépendent ces composants sont obtenus à partir du conteneur
      • public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport
    • 4、WebMvcAutoConfiguration La configuration à l'intérieur doit satisfaire à cette condition pour être efficace :@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
    • 5、@EnableWebMvc A conduit à WebMvcAutoConfiguration Non en vigueur.

9.2 Suite d'analyse de principe

Scénariostarter –> xxxxAutoConfiguration --> @BeanImporterxxxComponents --> BINDxxxProperties --> Lier les éléments du profil

Cinq.Accès aux données

1.SQL

1.1 Configuration automatique des sources de données-HikariDataSource

1)、ImporterJDBCScénario

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>

[Impossible de transférer l'image de la chaîne externe,Il peut y avoir un mécanisme antivol à la station source,Il est recommandé de sauvegarder l'image et de la télécharger directement(img-BfzRPyCb-1641479793660)(image/33.jpg)]

Importer un pilote de base de données

Pourquoi importerJDBCScénario,Official does not import Drives?

Les autorités ne savent pas quelle base de données nous allons utiliser.

<!-- Version par défaut-->
<mysql.version>8.0.22</mysql.version>
<!-- La version de la base de données correspond à la version du pilote -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<!-- <version>5.1.49</version> -->
</dependency>
<!-- Pour modifier la version: 1、Dépendance directe à l'introduction d'une version spécifique(mavenLe principe de la dépendance à proximité) 2、Redéclarer la version(mavenLe principe de la priorité la plus proche pour les propriétés de) -->
<properties>
<java.version>1.8</java.version>
<mysql.version>5.1.49</mysql.version>
</properties>

2)、Analyse de la configuration automatique

  • DataSourceAutoConfiguration : Configuration automatique des sources de données

    • Modifier la configuration liée à la source de données:spring.datasource
    • Configuration du pool de connexion à la base de données,Il n'y a pas deDataSourceSeulement configuré automatiquement
    • Le pool de connexion configuré sous - jacent est:HikariDataSource
@Configuration(proxyBeanMethods = false)
@Conditional(PooledDataSourceCondition.class)
@ConditionalOnMissingBean({
 DataSource.class, XADataSource.class })
@Import({
 DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Tomcat.class,
DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.OracleUcp.class,
DataSourceConfiguration.Generic.class, DataSourceJmxConfiguration.class })
protected static class PooledDataSourceConfiguration{

}
  • DataSourceTransactionManagerAutoConfiguration: Configuration automatique du gestionnaire de transaction

  • JdbcTemplateAutoConfiguration: JdbcTemplateConfiguration automatique pour,Peut venir à la base de données pourcrud

    • Vous pouvez utiliser cet élément de configuration @ConfigurationProperties(prefix = “spring.jdbc”) JdbcProperties Pour modifierJdbcTemplate
    • @[email protected] JdbcTemplate;Il y a ce composant dans le conteneur
  • JndiDataSourceAutoConfiguration: jndiConfiguration automatique pour

  • XADataSourceAutoConfiguration: Transactions distribuées liées à

3)、Modifier l'élément de configuration

mysql5.5Version

spring:
datasource:
url: jdbc:mysql://localhost:3306/testdb
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver

mysql8Version

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/testspring?serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=123456

4)、Tests

@Slf4j
@SpringBootTest
class Boot05WebAdminApplicationTests {

@Autowired
JdbcTemplate jdbcTemplate;
@Test
void contextLoads() {

Long aLong = jdbcTemplate.queryForObject("select count(*) from account_tbl", Long.class);
log.info("Nombre total d'enregistrements:{}",aLong);
}
}

1.2 UtiliserDruidSource des données

1)、druidOfficiellementgithubAdresse

https://github.com/alibaba/druid

Deux façons d'intégrer la technologie des tiers

  • Personnalisation
  • starter

2)、Mode personnalisé

Première étape:Basculer la source de donnéesDruidDataSource

https://mvnrepository.com/artifact/com.alibaba/druid

<!-- IntroductiondruidDépendance -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.22</version>
</dependency>

AvantxmlDans le profil,Configurer comme suit::

<!-- Configurer la source de données -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="maxActive" value="20" />
<property name="initialSize" value="1" />
<property name="maxWait" value="60000" />
<property name="minIdle" value="1" />
<property name="timeBetweenEvictionRunsMillis" value="60000" />
<property name="minEvictableIdleTimeMillis" value="300000" />
<property name="testWhileIdle" value="true" />
<property name="testOnBorrow" value="false" />
<property name="testOnReturn" value="false" />
<property name="poolPreparedStatements" value="true" />
<property name="maxOpenPreparedStatements" value="20" />
</bean>

On peut y réfléchir. ,SpringBootComment configurerDruidDataSourceComponents?

[email protected] + @BeanMode combiné,ConfigurationDruidDataSourceSource des données

@Configuration
public class MyDruidDataSourceConfig {

/** * [email protected] * DruidDataSource Les composants sont configurés dans IOCDans le récipient * * [email protected](prefix = "spring.datasource") * Configurer la liaison,application.yml .La configuration de la source de données définie dans le fichier peut être utilisée directement */
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DruidDataSource druidDataSource(){

DruidDataSource dataSource = new DruidDataSource();
return dataSource;
}
}
Deuxième étape:StatViewServlet

StatViewServletLes utilisations comprennent::

  • Fournir des informations de surveillancehtmlPage
  • Fournir des informations de surveillanceJSON API

Avantweb.xmlDans le profil,Configurer comme suit::

<servlet>
<servlet-name>DruidStatView</servlet-name>
<servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DruidStatView</servlet-name>
<url-pattern>/druid/*</url-pattern>
</servlet-mapping>

On peut y réfléchir. ,SpringBootComment configurerStatViewServletComponents?

[email protected] + @BeanMode combiné,ConfigurationStatViewServletSource des données

@Configuration
public class MyDruidDataSourceConfig {

/** * [email protected] * DruidDataSource Les composants sont configurés dans IOCDans le récipient * * [email protected](prefix = "spring.datasource") * Configurer la liaison,application.yml .La configuration de la source de données définie dans le fichier peut être utilisée directement */
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DruidDataSource druidDataSource(){

DruidDataSource dataSource = new DruidDataSource();
return dataSource;
}
//ConfigurationStatViewServlet Fournir des informations de surveillancehtmlPage
@Bean
public ServletRegistrationBean<StatViewServlet> servletRegistrationBean(){

StatViewServlet statViewServlet = new StatViewServlet();
ServletRegistrationBean<StatViewServlet> bean =
new ServletRegistrationBean<>(statViewServlet,"/druid/*");
// Nom d'utilisateur et mot de passe connectés sur la configuration 
bean.addInitParameter("loginUsername","admin");
bean.addInitParameter("loginPassword","admin");
// Interdiction de vider les statistiques 
bean.addInitParameter("resetEnable","false");
return bean;
}
}
Troisième étape:StatFilter

Pour les informations statistiques de surveillance;Par exemple:SQLSurveillance、URISurveillance

<!-- J'ai besoin de Source des données Les propriétés suivantes sont configurées dans ;Plusieurs peuvent être autorisésfilter,Plusieurs utilisations,Diviser;Par exemple: -->
<property name="filters" value="stat,slf4j" />

Tous dans le systèmefilter:

Alias FilterNom de la classe
default com.alibaba.druid.filter.stat.StatFilter
stat com.alibaba.druid.filter.stat.StatFilter
mergeStat com.alibaba.druid.filter.stat.MergeStatFilter
encoding com.alibaba.druid.filter.encoding.EncodingConvertFilter
log4j com.alibaba.druid.filter.logging.Log4jFilter
log4j2 com.alibaba.druid.filter.logging.Log4j2Filter
slf4j com.alibaba.druid.filter.logging.Slf4jLogFilter
commonlogging com.alibaba.druid.filter.logging.CommonsLogFilter
/** * [email protected] * DruidDataSource Les composants sont configurés dans IOCDans le récipient * * [email protected](prefix = "spring.datasource") * Configurer la liaison,application.yml .La configuration de la source de données définie dans le fichier peut être utilisée directement */
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DruidDataSource druidDataSource() throws SQLException {

DruidDataSource dataSource = new DruidDataSource();
//OuvertSQLSurveillance、 Surveillance du pare - feu 、Surveillance des journaux
dataSource.setFilters("stat,wall,slf4j");
return dataSource;
}
Quatrième étape:WebStatFilter

Pour la collecteweb-jdbcDonnées associées à la surveillance.

[email protected] + @BeanMode combiné,ConfigurationWebStatFilterSource des données.

//WebStatFilterPour la collecteweb-jdbcDonnées associées à la surveillance.
@Bean
public FilterRegistrationBean<WebStatFilter> filterRegistrationBean(){

WebStatFilter webStatFilter = new WebStatFilter();
FilterRegistrationBean<WebStatFilter> bean = new FilterRegistrationBean<WebStatFilter>();
bean.setFilter(webStatFilter);
bean.addInitParameter("exclusions","*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
bean.setUrlPatterns(Arrays.asList("/*"));
return bean;
}

Accès:http://localhost:8080/druid/datasource.html VoirdruidC'est exact.SQLSuivi de la situation

3)、Utilisation officiellestarterComment

https://github.com/alibaba/druid/tree/master/druid-spring-boot-starter

Première étape:Introductiondruid-starter
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.17</version>
</dependency>
Deuxième étape:Analyse de la configuration automatique
  • DruidDataSourceAutoConfigure.class,Extension des éléments de configuration spring.datasource.druid
  • DruidSpringAopConfiguration.class, SurveillanceSpringBeanDe;Éléments de configuration:spring.datasource.druid.aop-patterns
  • DruidStatViewServletConfiguration.class, Configuration de la page de surveillance:spring.datasource.druid.stat-view-servlet;Par défaut
  • DruidWebStatFilterConfiguration.class, webConfiguration de surveillance;spring.datasource.druid.web-stat-filter;Par défaut
  • DruidFilterConfiguration.class, Tous lesDruidMoi - même.filterConfiguration de
private static final String FILTER_STAT_PREFIX = "spring.datasource.druid.filter.stat";
private static final String FILTER_CONFIG_PREFIX = "spring.datasource.druid.filter.config";
private static final String FILTER_ENCODING_PREFIX = "spring.datasource.druid.filter.encoding";
private static final String FILTER_SLF4J_PREFIX = "spring.datasource.druid.filter.slf4j";
private static final String FILTER_LOG4J_PREFIX = "spring.datasource.druid.filter.log4j";
private static final String FILTER_LOG4J2_PREFIX = "spring.datasource.druid.filter.log4j2";
private static final String FILTER_COMMONS_LOG_PREFIX = "spring.datasource.druid.filter.commons-log";
private static final String FILTER_WALL_PREFIX = "spring.datasource.druid.filter.wall";
Troisième étape:Exemple de configuration
spring:
# Configurer les informations de base de la source de données 
datasource:
#JDBCConfiguration des propriétés
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/test?unicode=true&characterEncode=utf8&serverTimezone=GMT%2B8
username: root
password: root
#PourDruidConfiguration de la source de données
druid:
#SurveillanceSpringBean,OuvertSpringSurveillance
aop-patterns: com.igeek.springboot.*
#OuvertSQLSurveillance、 Surveillance du pare - feu 、Surveillance des journaux
filters: stat,wall,slf4j
#Pour la collecteweb-jdbcDonnées associées à la surveillance
web-stat-filter:
enabled: true #OuvertwebSurveillance
url-pattern: /*
exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"
#Fournir des informations de surveillancehtmlPage
stat-view-servlet:
enabled: true #OuverthtmlPrésentation de la page
url-pattern: /druid/*
login-username: admin
login-password: 123
reset-enable: false # Ne pas vider le bouton statistiques 
#Configuration détaillée
filter:
#stat SQLSurveillance,En hautfiltersÀ l'intérieur.statConfiguration détaillée de
stat:
enabled: true #OuvertSQLSurveillance
log-slow-sql: true # Activer la surveillance lente des journaux 
slow-sql-millis: 1000 #Unitésms,SQL Combien de temps l'exécution est lente ,Actuellement défini àsqlMise en œuvre>1s Même si c'est lent 
#wall Pare - feu,En hautfiltersÀ l'intérieur.wallConfiguration détaillée de
wall:
enabled: true
config:
selelct-allow: false #Requête interdite
alter-table-allow: false # Ne modifiez pas le tableau 
drop-table-allow: true # Autoriser la suppression de tableaux 

Liste des éléments de configurationhttps://github.com/alibaba/druid/wiki/DruidDataSource%E9%85%8D%E7%BD%AE%E5%B1%9E%E6%80%A7%E5%88%97%E8%A1%A8

1.3 IntégrationMyBatisFonctionnement

https://github.com/mybatis

starter

SpringBootOfficialStarter:spring-boot-starter-*

Tiers: *-spring-boot-starter

<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.4</version>
</dependency>

[Impossible de transférer l'image de la chaîne externe,Il peut y avoir un mécanisme antivol à la station source,Il est recommandé de sauvegarder l'image et de la télécharger directement(img-BIB6ws4r-1641479793661)(image/1606704096118-53001250-a04a-4210-80ee-6de6a370be2e.png)]

1)、Mode de configuration

  • Profil global
  • SqlSessionFactory: Configuré automatiquement
  • SqlSession:Configuré automatiquement SqlSessionTemplate Ensemble.SqlSession
  • @Import(AutoConfiguredMapperScannerRegistrar.class);
  • Mapper: Tant qu'on écritMyBatisNormes d'interface pour @Mapper Il sera automatiquement scanné
@EnableConfigurationProperties(MybatisProperties.class) // MyBatisClasse de liaison des éléments de configuration.
@AutoConfigureAfter({
 DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class })
public class MybatisAutoConfiguration{

}
@ConfigurationProperties(prefix = "mybatis")
public class MybatisProperties{

}

Vous pouvez modifier mybatis Tout a commencé:

# ConfigurationmybatisLes règles
mybatis:
config-location: classpath:mybatis/mybatis-config.xml #Emplacement du profil mondial
mapper-locations: classpath:mybatis/mapper/*.xml #sqlEmplacement du fichier de cartographie
<!-- MapperInterface > BINDXml -->
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.igeek.springboot.mapper.UserMapper">
<select id="getUser" paramterType="int" resultType="com.igeek.springboot.bean.User">
select * from user where id=#{id}
</select>
</mapper>

Configuration private Configuration configuration; mybatis.configurationTout en bas,C'est l'équivalent de changermybatisValeurs dans le profil global

# ConfigurationmybatisLes règles
mybatis:
#config-location: classpath:mybatis/mybatis-config.xml
mapper-locations: classpath:mybatis/mapper/*.xml
configuration:
map-underscore-to-camel-case: true #Nom de la bosse ouverte
#Peut ne pas écrire global;Profil,La configuration de tous les profils globaux est placée dansconfigurationDans l'élément de configuration

Modèle de configuration de consolidation ,Étapes de développement:

  • ImportermybatisOfficiellementstarter

  • CompilationmapperInterface.Critè[email protected]

  • CompilationsqlMapper le fichier et liermapperInterface

  • Inapplication.yamlSpécifié dansMapperEmplacement du profil,Et des informations pour spécifier le profil global (SuggestionConfiguré dansmybatis.configuration

2)、Mode annotation

@Mapper
public interface CityMapper {

@Select("select * from city where id=#{id}")
public City getById(Long id);
public void insert(City city);
}

3)、Mode mixte

@Mapper
public interface CityMapper {

@Select("select * from city where id=#{id}")
public City getById(Long id);
public void insert(City city);
}

Meilleure pratique:

  • Introductionmybatis-starter
  • Configurationapplication.yamlMoyenne,Désignationmapper-locationPosition.
  • CompilationMapperInterface et [email protected]
  • Méthode simple annotation directe méthode
  • Rédaction de méthodes complexesmapper.xmlFaire une cartographie de liaison
  • @MapperScan(“com.igeek.springboot.mapper”) Simplification,D'autres interfaces peuvent être non marqué[email protected]

1.4 IntégrationMyBatis-Plus

1)、Qu'est - ce queMyBatis-Plus

MyBatis-Plus(Abréviations MP)C'est un MyBatis Outils d'amélioration pour,In MyBatis Basé sur l'amélioration sans changement,Pour simplifier le développement、L'amélioration de l'efficacité.

mybatis plus Site officiel

Installation recommandée MybatisX Plug - in

Caractéristiques:

Humidification silencieuse

Faire des améliorations sans changement,Son introduction n'aura pas d'impact sur les travaux existants,Lisse comme de la soie.

Efficacité avant tout

Configuration simple,Ça peut être rapide CRUD Fonctionnement,Ce qui permet d'économiser beaucoup de temps.

Fonctions riches

Chargement à chaud、Génération de code、Pagination、Des fonctions telles que l'analyse de performance sont disponibles.

2)、IntégrationMyBatis-Plus

Première étape:Introduire des dépendances
<!-- mybatis-plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.1</version>
</dependency>

Attention!:Introduction MyBatis-Plus Ne pas réintroduire après MyBatis,Pour éviter les problèmes dus aux différences de version.mysql La dépendance doit être introduite par soi - même .

Deuxième étape: En savoir plus sur la configuration automatique
  • MybatisPlusAutoConfiguration Configurer la classe,MybatisPlusProperties Liaison de l'élément de configuration.mybatis-plus:xxx C'est ça.mybatis-plusSur mesure
  • SqlSessionFactory Auto - configuré.Le niveau inférieur est la source de données par défaut dans le conteneur
  • mapperLocations Configuré automatiquement.Il y a une valeur par défaut.classpath*:/mapper/**/*.xml;Tout sous le chemin de classe de n'importe quel paquetmapperTout sous n'importe quel chemin sous le dossierxmlTous.sqlFichier de cartographie. Suggérez que plus tardsqlFichier de cartographie,Mettez - le sur mapperEn bas..
  • Le conteneur est également automatiquement configuréSqlSessionTemplateObjet de session
  • @Mapper Les interfaces marquées sont également scannées automatiquement; Ou directement sur la classe de configuration principale [email protected](“com.igeek.springboot.mapper”) Numérisation par lots.
Troisième étape:Profil

In application.propertiesOuyaml Ajouter au profil MySQL Configuration de la base de données:

application.properties

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?unicode=true&characterEncode=utf8&serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=root

application.yml

spring:
# Configurer les informations de base de la source de données 
datasource:
#JDBCConfiguration des propriétés
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/test?unicode=true&characterEncode=utf8&serverTimezone=GMT%2B8
username: root
password: root

Attention!:

1、Ici. url Utilisé ?serverTimezone=GMT%2B8 Suffixe,Parce que8.0VersionjdbcLe pilote doit ajouter ce suffixe,Sinon, l'exécution du cas d'essai a signalé l'erreur suivante:

java.sql.SQLException: The server time zone value ‘Öйú±ê׼ʱ¼ä’ is unrecognized or represents more

2、Ici. driver-class-name Utilisé com.mysql.cj.jdbc.Driver ,In jdbc 8 Moyenne Cet entraînement est recommandé,Sinon, il y aura WARN Information

Quatrième étape:Classe de démarrage

In Spring Boot Ajouter à la classe de démarrage @MapperScan Notes,Scan Mapper Dossiers

@SpringBootApplication
@MapperScan("com.igeek.springboot.mapper")
public class DemomptestApplication {

public static void main(String[] args) {

SpringApplication.run(DemomptestApplication.class, args);
}
}
Étape 5:Classe d'entité

Créer un paquet entity Écrire une classe d'entité User.java(Utilisé ici Lombok Code simplifié)

Les données du tableau sont disponibles sur le site officiel

@Data
public class User {

private Long id;
private String name;
private Integer age;
private String email;
}
Étape 6:mapperCartographie

Créer un paquet mapper CompilationMapper Interface

UserMapper.java

@Repository
public interface UserMapper extends BaseMapper<User> {

}
Étape 7:serviceLes affaires

Créer un paquet serviceCompilationIService InterfaceUserService.java

public interface UserService extends IService<User> {

}

Créer un paquet serviceCompilationUserServiceImplCatégorie de mise en œuvre

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper,User> implements UserService {

}
Étape 8:VoirsqlJournal de sortie
#mybatisLog
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
Étape 9:Tests
@SpringBootTest
class SpringbootCh05MybatisplusApplicationTests {

@Autowired
private UserService userService;
//Liste des requêtes
@Test
public void testSelectAll(){

//SELECT id,name,age,email FROM user
List<User> list = userService.list(null);
System.out.println(list);
}
}

3)、CRUD - Requête

1.Requête
1.1 Par plusieursidRequête par lots

Dynamique terminéesqlDeforeachLa fonction de

//Par plusieursidRequête par lots
@Test
public void testSelectByIds(){

//SELECT id,name,age,email FROM user WHERE id IN ( ? , ? , ? )
List<User> list = userService.listByIds(Arrays.asList(1,2,3));
System.out.println(list);
}
1.2 Requête de condition simple

AdoptionmapEncapsuler les critères de requête

Attention!:mapDanskeyNom de colonne dans la base de données correspondante.Par exemple::Base de donnéesuser_id,La classe d'entité estuserId,À ce moment - là,mapDekeyÀ rempliruser_id

//Requête de condition simple
@Test
public void testSelectByMap(){

//MapEnsemblekey Assurez - vous de correspondre aux champs du tableau 
Map<String,Object> map = new HashMap();
map.put("name","Jone");
map.put("age",18);
//SELECT id,name,age,email FROM user WHERE name = ? AND age = ?
List<User> list = userService.listByMap(map);
System.out.println(list);
}
2.Pagination
2.1 Module de pagination

MyBatis PlusAvec plug - in de pagination,.La fonction de pagination peut être réalisée avec une configuration simple

2.1.1 Ajouter un plug - in de pagination

Ajouter à la classe de [email protected]

import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyConfig {

// Ajouter un plug - in de pagination à IOCDans le récipient
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {

MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// Ajouter un intercepteur interne 
PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();
// Définir la page demandée plus grande que la page maximale après l'opération, trueRetour à la page d'accueil,false Continuez à demander Par défautfalse
// paginationInnerInterceptor.setOverflow(false);
// Fixer la limite maximale d'une page,Par défaut 500 Article (s),-1 Illimité
paginationInnerInterceptor.setMaxLimit(-1L);
interceptor.addInnerInterceptor(paginationInnerInterceptor);
return interceptor;
}
}

2.1.2 TestsselectPagePagination

Tests:Adoption finalepageObjet obtenir les données pertinentes

//Requête pagée
@Test
public void testSelectPage() {

Page<User> page = new Page(1,3);
//Renvoie l'objet pour toutes les données pagées
Page<User> userPage = userMapper.selectPage(page, null);
//Nombre total de pages
long pages = userPage.getPages();
//Page actuelle 
long current = userPage.getCurrent();
//Interrogation des ensembles de données
List<User> records = userPage.getRecords();
//Total des enregistrements
long total = userPage.getTotal();
//Page suivante
boolean hasNext = userPage.hasNext();
//Page précédente
boolean hasPrevious = userPage.hasPrevious();
System.out.println(pages);
System.out.println(current);
System.out.println(records);
System.out.println(total);
System.out.println(hasNext);
System.out.println(hasPrevious);
}

2.1.3 TestsselectMapsPagePagination

Lorsqu'une colonne de requête spécifique est spécifiée,.Vous voulez que la liste des résultats de pagination ne renvoie que les colonnes demandées,Pas beaucoup.nullValeur

TestsselectMapsPagePagination:L'ensemble de résultats estMap

@Test
public void testSelectMapsPage() {

//PagePas besoin de génériques
Page<Map<String, Object>> page = new Page<>(1, 5);
Page<Map<String, Object>> pageParam = userMapper.selectMapsPage(page, null);
List<Map<String, Object>> records = pageParam.getRecords();
records.forEach(System.out::println);
System.out.println(pageParam.getCurrent());
System.out.println(pageParam.getPages());
System.out.println(pageParam.getSize());
System.out.println(pageParam.getTotal());
System.out.println(pageParam.hasNext());
System.out.println(pageParam.hasPrevious());
}
2.2 ControllerNiveau de contrôle
//Requête pagée
@GetMapping("/dynamic_table")
public String findAllByPage(
@RequestParam(value="now",defaultValue="1") Integer pageNow,
Model model
){

//EncapsulationPageObjet Premier paramètre:Page actuelle Deuxième paramètre: Combien d'enregistrements sont affichés par page 
IPage page = new Page(pageNow,2);
//ServiceOffrepagePour la pagination
IPage userPage = userService.page(page);
/** * Placer les données dans le champ de demande * records Liste des enregistrements * total Total des enregistrements * size Afficher les entrées par page * current Page actuelle * pages Nombre total de pages */
model.addAttribute("page",userPage);
return "table/dynamic_table";
}
2.3 Page
<tbody>
<tr class="gradeX" th:each="user : ${page.records}">
<td>[[${user.id}]]</td>
<td th:text="${user.name}">Internet</td>
<td th:text="${user.age}">Win 95+</td>
<td th:text="${user.email}">4</td>
<td>
<input type="button" class="btn btn-danger" value="Supprimer" /> |
<input type="button" class="btn btn-warning" value="Modifier" />
</td>
</tr>
</tbody>
<div class="span6">
<div class="dataTables_info" id="dynamic-table_info">
Total[[${page.pages}]]Nombre de pages,Total[[${page.total}]]Nombre d & apos; enregistrements,
Current No.[[${page.current}]](En milliers de dollars des États - Unis),Afficher par page[[${page.size}]]Enregistrement
</div>
</div>
<div class="dataTables_paginate paging_bootstrap pagination">
<ul>
<li class="prev disabled" th:class="${page.current eq 1}?'prev disabled':'prev'">
<a th:href="@{/dynamic_table(now=${page.current}-1)}">← Previous</a>
</li>
<li class="active" th:class="${now eq page.current}?'active':''" th:each="now : ${#numbers.sequence(1,page.pages)}">
<a th:href="@{/dynamic_table(now=${now})}">[[${now}]]</a>
</li>
<li class="next" th:class="${page.current eq page.pages}?'next disabled':'next'">
<a th:href="@{/dynamic_table(now=${page.current}+1)}">Next → </a>
</li>
</ul>
</div>

4)、CRUDFonction - Ajouter

1.MPStratégie clé primaire pour
ASSIGN_ID Stratégie

MyBatis-PlusLa politique par défaut de la clé primaire est:ASSIGN_ID (Avec l'algorithme flocon de neige)

@TableId(type = IdType.ASSIGN_ID)
private String id;

Algorithme flocon de neige:DistribuéIDGénérateur

L'algorithme flocon de neige estTwitterAlgorithme de génération de clés primaires distribuées annoncé,Il assure la non - répétition des clés primaires des différentes tables,Et l'ordre des clés primaires du même tableau.

L'idée centrale:

Longueur totale64bit(UnlongType).

D'abord un bit de symbole,1bitIdentification,Parce quelongType de baseJavaSigné au milieu,Le BIT le plus élevé est le BIT de symbole,Nombre positif oui0,Le nombre négatif est1,Alors...idGénéralement positif,La position la plus élevée est0.

41bitÉchéancier(Milliseconde),Ce qui est stocké est la différence de temps(Heure actuelle - Coupure de l'heure de début),Le résultat est approximativement égal à69.73Année.

10bitEn tant que machineID(5- Oui.bitC'est le Centre de données,5- Oui.bitMachinesID,Peut être déployé dans1024Noeuds).

12bitComme numéro de série en millisecondes(Cela signifie que chaque noeud peut produire 4096 - Oui. ID).

[Impossible de transférer l'image de la chaîne externe,Il peut y avoir un mécanisme antivol à la station source,Il est recommandé de sauvegarder l'image et de la télécharger directement(img-PGVNlK9C-1641479793662)(image/image-20210406131246721.png)]

Avantages:Dans l'ensemble, par ordre croissant de temps,Et ne se produira pas dans l'ensemble du système distribuéIDCollisions,Et plus efficace.

AUTO Stratégie d'auto - augmentation

Vous devez définir l'auto - augmentation de la clé primaire lors de la création de la table de données

Configuration dans le champ entité @TableId(type = IdType.AUTO)

@TableId(type = IdType.AUTO)
private Long id;

Pour influencer la configuration de toutes les entités,La configuration globale de la clé primaire peut être définie

#Définir globalement la politique de génération de clés primaires
mybatis-plus.global-config.db-config.id-type=auto
2.Opération d'insertion
//Ajouter
@Test
public void testAdd() {

User user = new User();
user.setName("lucy");
user.setAge(20);
user.setEmail("[email protected]");
int insert = userMapper.insert(user);
System.out.println(insert);
}

5)、CRUDFonction - Supprimer

1.Suppression physique
1.1 SelonidSupprimer l'enregistrement
@Test
public void testDeleteById(){

int result = userMapper.deleteById(5L);
system.out.println(result);
}
1.2 Suppression par lots
@Test
public void testDeleteBatchIds() {

int result = userMapper.deleteBatchIds(Arrays.asList(8, 9, 10));
system.out.println(result);
}
1.3 Condition simple supprimer
@Test
public void testDeleteByMap() {

HashMap<String, Object> map = new HashMap<>();
map.put("name", "Helen");
map.put("age", 18);
int result = userMapper.deleteByMap(map);
system.out.println(result);
}

ControllerCouche

@Autowired
private UserService userService;
@GetMapping("/user/delete/{id}")
public String deleteUser(@PathVariable("id") Long id,
@RequestParam(value = "pn",defaultValue = "1")Integer pn,
RedirectAttributes ra){

userService.removeById(id);
ra.addAttribute("pn",pn);
return "redirect:/dynamic_table";
}
2.Suppression logique
2.1 Suppression physique et logique

**Suppression physique:**Suppression réelle,Supprimer les données correspondantes de la base de données,Cette entrée n'a pas été supprimée après la requête

**Suppression logique:**Fausse suppression,Modifier l'état du champ représentant si les données correspondantes sont supprimées à“État supprimé”,Cet enregistrement de données peut encore être vu dans la base de données plus tard

Scénario d'utilisation pour la suppression logique:

La récupération des données peut être effectuée

Il y a des données associées,Inconvénient à supprimer

Analyser le comportement du client

2.2 Processus de mise en oeuvre de la suppression logique

2.2.1 Modification de la base de données

Ajouter deletedChamp

ALTER TABLE `user` ADD COLUMN `deleted` int DEFAULT 0;

2.2.2 Modification de la classe d'entité

Ajouterdeleted Champ,Et ajouter @TableLogic Notes

@TableLogic
private Integer deleted;

2.2.3 Configuration(Facultatif)

application.properties Ajouter la configuration suivante,C'est la valeur par défaut,Si vos valeurs par défaut etmpPar défaut,Cette configuration peut ne pas avoir

mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0

2.2.4 Tests

Les tests ont révélé que,Les données n'ont pas été supprimées,deletedLa valeur du champ est déterminée par0Est devenu1

Analyse post - test imprimersqlDéclarations,C'est unupdate

Attention!:Avant d'être supprimé,Les donnéesdeleted La valeur du champ doit être 0,Pour être sélectionné pour effectuer une opération de suppression logique

@Test
public void testLogicDelete() {

int result = userMapper.deleteById(1L);
system.out.println(result);
}

2.2.5 Requête après suppression de la logique de test

MyBatis PlusL'opération de requête ajoutera également automatiquement le jugement du champ de suppression logique

@Test
public void testLogicDeleteSelect() {

List<User> users = userMapper.selectList(null);
users.forEach(System.out::println);
}

6)、CRUDFonction - Modifier(Remplissage automatique et verrouillage optimiste)

1.Opération de mise à jour

Attention!:updateGénéré àsqlAutomatique est dynamiquesql

UPDATE user SET age=? WHERE id=?
//Modifier
@Test
public void testUpdate() {

User user = new User();
user.setId(1340868235401764865L);
user.setName("lucymary");
int count = userMapper.updateById(user);
System.out.println(count);
}
2.Remplissage automatique

Description des exigences:

On rencontre souvent des données dans les projets,Remplir de la même façon à chaque fois,Par exemple, le temps de création de l'enregistrement,Temps de mise à jour, etc..

On peut utiliserMyBatis PlusFonction de remplissage automatique pour,Terminer l'affectation de ces champs

1.1 Modification de la base de données

InUserAjouter au tableaudatetimeNouveau champ pour le type create_time、update_time

1.2 Modification de la classe d'entité

Ajouter un champ sur l'entité et ajouter une annotation de remplissage automatique

//create_time
@TableField(fill = FieldFill.INSERT)
private Date createTime;
//update_time
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
1.3 Implémenter l'interface du processeur de méta - objets

Attention!:N'oubliez pas d'ajouter @Component Notes

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

//mpEffectuer une opération d'ajout,Cette méthode exécute 
@Override
public void insertFill(MetaObject metaObject) {

this.setFieldValByName("createTime",new Date(),metaObject);
this.setFieldValByName("updateTime",new Date(),metaObject);
}
//mpEffectuer des modifications,Cette méthode exécute 
@Override
public void updateFill(MetaObject metaObject) {

this.setFieldValByName("updateTime",new Date(),metaObject);
}
}
3、La serrure optimiste
Scénario

Principaux scénarios applicables:Lors de la mise à jour d'un enregistrement,J'espère que ce dossier n'a pas été mis à jour,C'est - à - dire la mise à jour des données pour la sécurité des Threads

Mise en œuvre de la serrure optimiste:

1.Lorsque vous retirez l'enregistrement,Obtenir le courantversion

2.Lors de la mise à jour,Prends çaversion

3.Lors de la mise à jour, set version = newVersion where version = oldVersion

4.SiversionNon,La mise à jour a échoué

4、Processus de mise en oeuvre de la serrure optimiste
4.1 Modifier la classe d'entité

Ajouter @Version Notes

@Version
private Integer version;
4.2 Créer un profil

Créer un paquetconfig,Créer un fichierMybatisPlusConfig.java

Vous pouvez maintenant Supprimer @MapperScan Scan annotation

@Configuration
public class MyConfig {

// Ajouter un plug - in à IOCDans le récipient
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {

MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
//Ajouter un plug - in de verrouillage optimiste
OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor = new OptimisticLockerInnerInterceptor();
interceptor.addInnerInterceptor(optimisticLockerInnerInterceptor);
return interceptor;
}
}

7)、Constructeurs conditionnels et interfaces communes

1.wrapperIntroduction

[Impossible de transférer l'image de la chaîne externe,Il peut y avoir un mécanisme antivol à la station source,Il est recommandé de sauvegarder l'image et de la télécharger directement(img-Uqkt8gOD-1641479793662)(image/wps1.jpg)]

Wrapper : Classe abstraite de construction conditionnelle,Parent supérieur

​ AbstractWrapper : Pour l'encapsulation des critères de requête,Générer sql De where Conditions

​ QueryWrapper : Encapsulation des critères de requête

​ UpdateWrapper : Update Conditionnement

AbstractLambdaWrapper : UtiliserLambda Syntaxe

​ LambdaQueryWrapper :PourLambdaRequêtes utilisées par la syntaxeWrapper

​ LambdaUpdateWrapper : Lambda Mise à jour de l'encapsulationWrapper

@SpringBootTest
public class QueryWrapperTests {

@Autowired
private UserMapper userMapper;
}
2.Cas d'essai
2.1 ge、gt、le、lt、isNull、isNotNull
@Test
public void testQuery() {

QueryWrapper<User>queryWrapper = newQueryWrapper<>();
queryWrapper.isNull("name").ge("age", 12).isNotNull("email");
int result = userMapper.delete(queryWrapper);
System.out.println("delete return count = " + result);
}
2.2 eq、ne

Attention!:seletOne()Renvoie un enregistrement physique,Une erreur est signalée lorsque plusieurs éléments apparaissent

@Test
public void testSelectOne() {

QueryWrapper<User>queryWrapper = newQueryWrapper<>();
queryWrapper.eq("name", "Tom");
Useruser = userMapper.selectOne(queryWrapper);
//Un seul enregistrement peut être retourné,Une exception est lancée pour l'autre
System.out.println(usr);
}
2.3 between、notBetween

Contient une limite de taille

@Test
public void testSelectCount() {

QueryWrapper<User>queryWrapper = newQueryWrapper<>();
queryWrapper.between("age", 20, 30);
Integer count = userMapper.selectCount(queryWrapper);
//Nombre de données retournées
System.out.println(count);
}
2.4 like、notLike、likeLeft、likeRight

selectMaps()RetourMapListe des collections,En général.select()Utiliser

@Test
public void testSelectMaps() {

QueryWrapper<User>queryWrapper = newQueryWrapper<>();
queryWrapper.select("name", "age").like("name", "e").likeRight("email", "5");
List<Map<String, Object>>maps = userMapper.selectMaps(queryWrapper);
//La valeur de retour estMapListe
maps.forEach(System.out::println);
}
2.5 orderBy、orderByDesc、orderByAsc
@Test
public void testSelectListOrderBy() {

QueryWrapper<User>queryWrapper = newQueryWrapper<>();
ueryWrapper.orderByDesc("age", "id");
List<User>users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
3.Mode de requête
Mode de requête Description
setSqlSelect Paramètres SELECT Champs de requête
where WHERE Déclarations,épissage + WHERE Conditions
and AND Déclarations,épissage + AND Champ=Valeur
andNew AND Déclarations,épissage + AND (Champ=Valeur)
or OR Déclarations,épissage + OR Champ=Valeur
orNew OR Déclarations,épissage + OR (Champ=Valeur)
eq égal à=
allEq Basé sur map Le contenu est égal à=
ne Pas égal à<>
gt Plus grand que>
ge Supérieur ou égal à>=
lt Moins de<
le Jusqu'à<=
like Requête floue LIKE
notLike Requête floue NOT LIKE
in IN Requête
notIn NOT IN Requête
isNull NULL Requête de valeur
isNotNull IS NOT NULL
groupBy Groupe GROUP BY
having HAVING Mots clés
orderBy Trier ORDER BY
orderAsc ASC Trier ORDER BY
orderDesc DESC Trier ORDER BY
exists EXISTS Déclaration conditionnelle
notExists NOT EXISTS Déclaration conditionnelle
between BETWEEN Déclaration conditionnelle
notBetween NOT BETWEEN Déclaration conditionnelle
addFilter Free Splice SQL
last L'épissage est à la fin,Par exemple:last(“LIMIT 1”)

2.NoSQL

​ Redis Est une source ouverte(BSDPermission)De,Structure des données en mémoire système de stockage,Il peut être utilisé comme base de données、CacheEt l'intergiciel de messagerie. Il prend en charge plusieurs types de structures de données,Par exemple: String(strings), Hachage(hashes), Liste(lists), Ensemble(sets), Rassemblement ordonné(sorted sets) Requête de portée, bitmaps, hyperloglogs Et Espace géographique(geospatial) Requête de rayon d'index. Redis Intégré Copier(replication),LUAScript(Lua scripting), LRUÉvénements moteurs(LRU eviction),Services(transactions) Et différents niveaux Persistance du disque(persistence), Et à travers RedisSentinelle(Sentinel)Et automatique Partition(Cluster)Offre une grande disponibilité(high availability).

2.1 RedisConfiguration automatique

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

[Impossible de transférer l'image de la chaîne externe,Il peut y avoir un mécanisme antivol à la station source,Il est recommandé de sauvegarder l'image et de la télécharger directement(img-14GpRXjQ-1641479793663)(image/34.jpg)]

Configuration automatique:

  • RedisAutoConfiguration Classe de configuration automatique.RedisProperties Classe de propriété --> spring.redis.xxxC'est vrai.redisConfiguration de
  • L'usine de connexion est prête.LettuceConnectionConfiguration、JedisConnectionConfiguration
  • Auto - injectionRedisTemplate<Object, Object> : xxxTemplate;
  • Auto - injectionStringRedisTemplate;k:vTous.String
  • key:value
  • Le rez - de - chaussée, tant qu'on l'utilise StringRedisTemplate、RedisTemplatePour pouvoir fonctionnerredis

redisConstruction de l'environnement

1、Alicloud Pay As You Goredis.Réseau classique

2、ApplicationredisAdresse de connexion au réseau public pour

3、Modifier la liste blanche Allow0.0.0.0/0 Accès à

2.2 RedisTemplateAvecLettuce

@Test
void testRedis(){

ValueOperations<String, String> operations = redisTemplate.opsForValue();
operations.set("hello","world");
String hello = operations.get("hello");
System.out.println(hello);
}

2.3 Passer àjedis

Première étape IntroductionjedisDépendance

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- Importerjedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>

Deuxième étape Connexion renforcée redis Le type de client pour est jedis

spring:
redis:
host: r-bp1nc7reqesxisgxpipd.redis.rds.aliyuncs.com
port: 6379
password: root:123456
client-type: jedis
jedis:
pool:
max-active: 10

Connexionredis Solutions échouées :
1. Voir s'il y a un démarrage RedisServeur.

2.redisConfiguration deapplication.yml(Ouapplication.properties)Moyenne
spring.redis.timeoutDélai de connexion(MS) Le réglage dans ne peut pas être 0,
Modifier comme suit: :spring.redis.timeout=5000.

3.TrouverredisProfil pour redis.conf : Mise en œuvre vim redis.conf
3.1 protected-mode yes Lire comme suit: protected-mode no ( C'est - à - dire que l'élément de configuration indique si le mode de protection est activé ,La valeur par défaut est activée,Après ouvertureRedisAccès local seulement,Accès externe refusé).
3.2 Note bin127.0.0.1 C'est - à - dire: #bin 127.0.0.1 (ps: Pas de commentaire.,Indique la désignation redis Ne recevoir que de IP Demande d'adresse,Après avoir noté, Indique que toutes les demandes seront traitées ).

​ 3.3 daemonize yes

4.Si dansRedisNon configuré dansrequirepass ,Alors, dansapplication.properties(Ouapplication.yaml) N'écrivez pas spring.redis.password.

版权声明:本文为[Vers le Haut]所创,转载请带上原文链接,感谢。 https://javamana.com/2022/01/202201080601055911.html