Vers le Haut 2022-01-15 02:47:13 阅读数:654
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
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.
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 configurationAutomatiquestarterDépendance,Simplifier la configuration de construction
Automatically configure Spring and 3rd party libraries whenever possibleConfiguration automatiqueSpringEt les fonctions de tiers
Provide production-ready features such as metrics, health checks, and externalized configurationSurveillance au niveau de la production、Configuration du bilan de santé et de l'externalisation
Absolutely no code generation and no requirement for XML configurationPas de génération de code、Pas besoin d'écrireXML
SpringBootC'est l'intégration.SpringUn guichet unique pour la pile technologiqueSpringBootC'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
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)]
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)]
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>
Besoins:Parcourir envoyer/helloDemande,Réponse “Hello,Spring Boot 2”
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>
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);
}
}
}
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!";
}
}
ExécutionMainApplicationCatégorie
Entrée du navigateurhttp://localhost:8888/hello,Affichage de la pageHello, Spring Boot 2!.
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
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)]
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.
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>
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 .
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>
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);
}
}
}
.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")
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.
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.
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);
}
}
@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);
}
}
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 .
[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
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 {
}
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);
}
}
}
Montage conditionnel:SatisfactionConditionalConditions spécifiées,Injecter les composants
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);
}
}
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);
}
}
Supposons que le projet original soit toujours SSMDe,Peut mettre tous lesxmlProfil,[email protected] Importer pour utilisation
<?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>
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 {
}
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
}
Comment utiliserJavaLire àpropertiesContenu du fichier,Et l'encapsule dansJavaBeanMoyenne,Pour une utilisation immédiate
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.
}
}
}
@ConfigurationProperties + @Component
myaddr.city=Jiangsu Wuxi
myaddr.street=New Wu District
<!-- IntroductionlombokDépendance -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
InFile -> Settings ->Plugins -> InstallationlombokPlug - in
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;
}
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());
}
}
@EnableConfigurationProperties + @ConfigurationProperties
myaddr.city=Jiangsu Wuxi
myaddr.street=New Wu District
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 {
}
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;
}
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());
}
}
Spring Boot Classe de démarrage de l'application
@SpringBootApplication
public class MainApplication {
public static void main(String[] args) {
SpringApplication.run(MainApplication.class, args);
}
}
@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.
@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.
Spécifier le paquet,Qu'est - ce queSpringNotes.
@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)
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.
@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,\
...
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.
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;
}
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;
}
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
Documents officiels
https://docs.spring.io/spring-boot/docs/current/reference/html/using-spring-boot.html#using-boot-starter
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)
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
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;
}
}
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.
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)]
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);
}
}
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.
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
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
@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}]
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>
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;
}
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
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.
# 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
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.
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
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
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;
}
@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;
//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 .
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
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>
@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";
}
# Ouvrir le formulaire de pageRestFonction(SoutienPUT、DELETE)
spring.mvc.hiddenmethod.filter.enabled=true
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;
}
}
}
Par exemple:PostMan Peut être envoyé directement put、deleteDemande par exemple.
@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_method
Modifier comme suit:_m
:
<form action="/user" method="post">
<input name="_m" type="hidden" value="DELETE"/>
<input value="REST-DELETE Soumettre" type="submit"/>
</form>
[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.handlerMappings
InDebug 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
Ethandler
Rè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 .
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
@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)]
/** * [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)]
/** * [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)]
/** * [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)]
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;
}
}
}
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
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
@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;
}
}
@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)]
Ensuite, regardons,Map map
AvecModel model
Avec quel processeur de paramètres .
Map map
ParamètresMapMethodProcessor
Traitement:
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 model
AvecModelMethodProcessor
Traitement:
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.MapMethodProcessor
Cohé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 InternalResourceView
Caté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);
}
});
}
}
exposeModelAsRequestAttributes
La 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.
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
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é.
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.
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/
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)]
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 |
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
Assemblage de chaînes: +
Substitution de variables: |The name is ${name}|
Opérateur: + , - , * , / , %
Opérateur: and , or
Opération univariée: ! , not
Comparaison: > , < , >= , <= ( gt , lt , ge , le )
Équation: == , != ( eq , ne )
If-then: (if) ? (then)
If-then-else: (if) ? (then) : (else)
Default: (value) ?: (defaultvalue)
Aucune opération: _
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>
<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>
<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>
[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)]
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
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
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">
@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";
}
}
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
UtiliserIDEADeSpring Initializr. Cochez l'initiateur :thymeleaf、web-starter、devtools、lombok.
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
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>
@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";
}
}
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>
@AllArgsConstructor
@NoArgsConstructor
@Data
public class User {
private String userName;
private String password;
}
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">
© 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>
© 2011 The Good Thymes Virtual Grocery
</foot>
</div>
<foot>
© 2011 The Good Thymes Virtual Grocery
</foot>
<div>
© 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>
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>
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)]
/** * 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);
}
}
/** * 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
}
}
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)]
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>
/** * 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";
}
**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)]
https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-error-handling
1.Par défaut,Spring BootOffre
/error
Traiter 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,Ajouter
View
La vue se résout àerror
.
4.Pour remplacer complètement le comportement par défaut,Peut être réalisé
ErrorController
Et 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)]
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";
}
}
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";
}
}
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";
}
}
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)]
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();
}
}
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 ;
ErrorMvcAutoConfiguration Configurer automatiquement les règles de gestion des exceptions
[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)]
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)]
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;
[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)]
[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)]
[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)]
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
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
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);
}
}
Extension:DispatchServlet Comment s'inscrire?
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 .
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
Scénariostarter –> xxxxAutoConfiguration --> @BeanImporterxxxComponents --> BINDxxxProperties --> Lier les éléments du profil
<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>
DataSourceAutoConfiguration : Configuration automatique des sources de données
@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
JndiDataSourceAutoConfiguration: jndiConfiguration automatique pour
XADataSourceAutoConfiguration: Transactions distribuées liées à
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
@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);
}
}
https://github.com/alibaba/druid
Deux façons d'intégrer la technologie des tiers
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;
}
}
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;
}
}
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;
}
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
https://github.com/alibaba/druid/tree/master/druid-spring-boot-starter
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.17</version>
</dependency>
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";
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
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)]
@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)
@Mapper
public interface CityMapper {
@Select("select * from city where id=#{id}")
public City getById(Long id);
public void insert(City city);
}
@Mapper
public interface CityMapper {
@Select("select * from city where id=#{id}")
public City getById(Long id);
public void insert(City city);
}
Meilleure pratique:
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é.
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.
<!-- 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 .
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
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);
}
}
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;
}
Créer un paquet mapper CompilationMapper Interface
UserMapper.java
@Repository
public interface UserMapper extends BaseMapper<User> {
}
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 {
}
#mybatisLog
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
@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);
}
}
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);
}
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);
}
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());
}
//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";
}
<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>
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.
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
//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);
}
@Test
public void testDeleteById(){
int result = userMapper.deleteById(5L);
system.out.println(result);
}
@Test
public void testDeleteBatchIds() {
int result = userMapper.deleteBatchIds(Arrays.asList(8, 9, 10));
system.out.println(result);
}
@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";
}
**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.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);
}
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);
}
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
InUserAjouter au tableaudatetimeNouveau champ pour le type create_time、update_time
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;
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);
}
}
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é
Ajouter @Version Notes
@Version
private Integer version;
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;
}
}
[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;
}
@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);
}
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);
}
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);
}
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);
}
@Test
public void testSelectListOrderBy() {
QueryWrapper<User>queryWrapper = newQueryWrapper<>();
ueryWrapper.orderByDesc("age", "id");
List<User>users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
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”) |
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).
<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:
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 à
@Test
void testRedis(){
ValueOperations<String, String> operations = redisTemplate.opsForValue();
operations.set("hello","world");
String hello = operations.get("hello");
System.out.println(hello);
}
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- Importerjedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
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