Pour les connaissances frontales, elles doivent être encore consolidées et renforcées. Après être entré dans l'entreprise, il est nécessaire d'avoir une certaine interface de débogage, une capacité de réception de paramètres et le développement d'une seule page. Ici, j'apprendrai le front- connaissances finales pour consolider ma propre pile technologique et mon niveau. Cette note est un cours du même nom que le cheval noir, pour consolider mon niveau de connaissance du front-end, et espérer l'utiliser dans l'industrie.
Connaissances frontales que les programmeurs Java doivent maîtriser
- avant-propos
- horaire de cours
- Objectifs du cours
- Chapitre 1. HTML et CSS
-
- 1. Éléments HTML
- 2. Pages HTML
- 3. Éléments communs
- 4. Requête HTTP
-
- 1) Demander la composition
- 2) Méthode de demande et format des données
- 3) principe de séance
- 4) principe jwt
- 5. CSS
avant-propos
Lorsque les programmeurs Java mentionnent les connaissances frontales, ils ont des sentiments mitigés et des sentiments mitigés.
- Dites ne l'apprenez pas, peut-être qu'après être entré dans l'entreprise, vous serez pris et écrirez du code frontal de temps en temps
- Apprenons-le, HTML, CSS, JavaScript, lequel ne peut être maîtrisé sans un travail acharné ?
- Apprendre un peu suffit-il ? Si seulement apprendre JavaScript de base ne suffit pas, le front-end a déjà été conçu. Vous pouvez aller voir les frameworks tels que Vue et React. Vous ne pouvez pas comprendre juste un peu de base, même où se trouve le chemin de la page frontale. configuré et comment sauter. Je sais très bien, donc je dois apprendre, et il y a encore beaucoup à apprendre. S'il vous plaît, apprenez le front-end en tant que partie intégrante du Web.
- Apprendre le front-end présente de nombreux avantages, j'ai entendu un dicton raisonnable : un programmeur doit maîtriser au moins un langage statique, tel que Java, et un langage dynamique, tel que JavaScript. De plus, ne pensez-vous pas qu'apprendre le front-end, c'est comme passer à travers les deux lignes du programmeur de Ren et Du, et que vous pouvez prendre en charge des tâches de manière indépendante ?
Pourquoi ce cours n'est-il pas enseigné par l'enseignant principal ?
- L'enseignant du front-end ne connaît pas les points faibles des élèves du back-end. Il pense que nous ne nous soucions pas des plus importants. Il pense que c'est du bon sens et c'est juste là que nous sommes confus. En tant que back-end enseignant, je comprends mieux les élèves du back-end.
- L'enseignant du front-end ne comprend pas les connaissances du back-end, il ne peut donc parler du front-end qu'avec la pensée du front-end. Si l'enseignant connaît Java, il peut utiliser certaines connaissances existantes pour comparer et expliquer, ce qui peut atteindre un effet de percée rapide
- Chaque framework front-end nécessite des dizaines d'heures d'étude, ce que nous ne pouvons pas nous permettre. Nous espérons apprendre la partie la plus utile pour nous. Gardez le reste, et nous ne pouvons pas enlever le travail des programmeurs front-end.
horaire de cours
- L'ensemble du cours est divisé en cinq chapitres
- HTML/CSS n'est pas le point clé pour nous, mais il faut en parler.Comme le premier chapitre, ces deux connaissances doivent être apprises
- JavaScript est le point clé, en particulier certaines nouvelles grammaires après ES6. Si vous ne les comprenez pas, vous ne pouvez pas du tout comprendre le code frontal. Vous devez apprendre
- Les trois chapitres Vue2, Vue3 et React sont l'un des trois. Selon les différentes technologies front-end utilisées par l'entreprise que vous rejoignez, apprenez de manière ciblée
- Les trois derniers chapitres couvriront l'utilisation de bibliothèques et d'outils tels que TypeScript, VueCli, Vuex, VueRouter, ElementUI, Vite, CreateReactApp, React, Redux, ReactRouter, etc.
- jquery Après recherche, certains étudiants l'utiliseront en effet après l'obtention de leur diplôme, il est donc également étudié en tant que chapitre optionnel
horaire de cours
Objectifs du cours
Chapitre 1. HTML et CSS
Qu'est-ce que HTML: c'est le langage de balisage hypertexte du langage HyperText Markup, les pages Web que nous connaissons y sont écrites et le rôle de HTML est de définir le contenu et la structure des pages Web.
Qu'est-ce que l'hypertexte, regardons les didacticiels fournis par les informations.
Pour plus de détails, voir Code\Chapitre 1\exemple1-Qu'est-ce que html et css 1.html
Cliquez sur la page 2
cliquez page 3
Alors, qu'est-ce que le langage de balisage ?
Faisons un clic droit et ouvrons-le avec VS Code.
Ces parties entre crochets sont appelées Markup. Dans le front-end, nous les appelons des onglets.
- HyperText fait référence à l'utilisation d'hyperliens pour organiser des pages Web et connecter des pages Web
- Le balisage fait référence à
<标签>
la façon de donner au contenu différentes fonctions et significations
Qu'est-ce que CSS : Feuilles de style en cascade Feuilles de style en cascade (en cascade), qui décrivent les performances et l'affichage des pages Web
Nous importons le style style.css.
Vous pouvez voir que la police et la couleur d'arrière-plan du lien hypertexte ont changé.
1. Éléments HTML
HTML elements
se compose d'une série d'éléments tels que
<p>Hello, world!</p>
-
éléments
-
<p>
et</p>
sont appelées balise de début et balise de fin, respectivement -
Bonjour, le monde entouré de balises s'appelle du contenu
-
p est une balise html prédéfinie, la fonction est de traiter le contenu comme un paragraphe séparé
Créez un nouveau fichier 3.html sous l'élément code\Chapter 1\example2-html et nous écrivons nous-mêmes un élément.
Le code est le suivant :
<p>Hello, world!</p>
Ouvrir avec un navigateur
L'effet est le suivant :
Si nous voulons augmenter le nombre d'étiquettes, copiez
ALT + SHIFT + ↓ via les touches de raccourci
pour afficher les résultats comme suit :
voici une petite astuce : si nous connaissons le raccourci clés d'IDEA, nous pouvons télécharger le plug-in et modifier les habitudes des touches de raccourci en IDEA
Les éléments peuvent également avoir des attributs, tels que
<p id="p1">Hello, world! 1</p>
<p id="p2">Hello, world! 2</p>
<p id="p3">Hello, world! 3</p>
<p id="p4">Hello, world! 4</p>
- Les attributs sont généralement prédéfinis. L'attribut id ici sert à donner à l'élément un identifiant unique
. En plus de cet attribut, on peut également ajouter l'attribut title
<p id="p1" title="标题1">Hello, world! 1</p>
<p id="p2">Hello, world! 2</p>
<p id="p3">Hello, world! 3</p>
<p id="p4">Hello, world! 4</p>
La page Web s'affiche comme suit : Au survol de la souris, le titre 1 apparaît
Les éléments peuvent être imbriqués, tels que
<p id="p1" title="标题1">Hello, world! 1 I am <b>Cony</b></p>
<p id="p2">Hello, world! 2</p>
<p id="p3">Hello, world! 3</p>
<p id="p4">Hello, world! 4</p>
Mauvaise écriture imbriquée :
Les étiquettes ne peuvent pas se croiser
<p>HTML 是一门非常<b>强大的语言</p></b>
Un élément qui ne contient pas de contenu est appelé un élément vide, tel que
<img src="1.png">
<img src="1.png"/>
- img est utilisé pour afficher des images
- L'attribut src est utilisé pour indiquer le chemin de l'image
2. Pages HTML
Les introductions précédentes ne sont que des éléments HTML individuels, qui peuvent faire partie intégrante d'une page HTML complète
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试页面</title>
</head>
<body>
<p id="p1">Hello, world!</p>
<img src="1.png">
</body>
</html>
html
L'élément inclut tous les autres éléments de la page, et un seul élément est nécessaire pour toute la page, appelé l'élément racinehead
Les éléments incluent des éléments qui ne sont pas utilisés pour afficher le contenu, tels quetitle
,link
,meta(指定编码)
etc.body
Les éléments incluent des éléments qui présentent du contenu aux utilisateurs, tels que divers éléments qui seront appris plus tard pour afficher du texte, des images, des vidéos et de l'audio
Dans le répertoire de page code\Chapter 1\example3-html, créez un nouveau fichier de page Web 2.html
Shortcut key!, vous pouvez directement générer le modèle html
Ici, nous modifions le code comme suit :
<!DOCTYPE html>
<!-- 网页展示为:中文(默认) -->
<html lang="zh">
<head>
<!-- 字符集编码 -->
<meta charset="UTF-8">
<!-- 浏览器的兼容模式(这里不用关心) -->
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!-- 视口 -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>这是一个完整页面</title>
</head>
<body>
<p>Hello World</p>
<img src="1.png">
</body>
</html>
L'effet après ouverture avec un navigateur est le suivant :
La largeur de l'image est relativement grande, réinitialisons la largeur des pixels
<img src="1.png" width="300">
Regardez le navigateur comme suit :
3. Éléments communs
1) texte
Titre
<h1>1号标题</h1>
<h2>2号标题</h2>
<h3>3号标题</h3>
<h4>4号标题</h4>
<h5>5号标题</h5>
<h6>6号标题</h6>
L'effet est le suivant :
Paragraphe
<p>段落</p>
spectacle de code comme ci-dessous
<p id="p1" title="悬浮1">段落1</p>
<p id="p2" title="悬浮2">段落2</p>
<p id="p3" title="悬浮3">段落3</p>
Effet:
Liste
liste non ordonnée liste non ordonnée
<ul>
<li>列表项1</li>
<li>列表项2</li>
<li>列表项3</li>
</ul>
liste
ordonnée liste ordonnée
<ol>
<li>列表项1</li>
<li>列表项2</li>
<li>列表项3</li>
</ol>
liste à plusieurs niveaux
<ul>
<li>
北京市
<ul>
<li>海淀区</li>
<li>朝阳区</li>
<li>昌平区</li>
</ul>
</li>
<li>
河北省
<ul>
<li>石家庄</li>
<li>保定</li>
</ul>
</li>
</ul>
Ancre
ancre, lien hypertexte
<a href="网页地址">超链接文本</a>
(1). Accéder à la page Web locale
Page Web locale (même répertoire)
<a href="2.html">本地网页</a>
(2) Accéder aux pages Internet
<a href="http://www.baidu.com">互联网网页</a>
après clic
(3) Aller au point d'ancrage dans la page
<a href="#p1">页面内锚点</a>
<hr>
<br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br>
<p id="p1">很下面的内容 <a href="#">回到顶部</a></p>
Après avoir cliqué, allez à la position de l'étiquette où se trouve p1
2) Multimédia
Image
<img src="文件路径">
Il existe 3 formats src
- adresse de fichier
Par exemple
<img src="heima.png">
- URL de données, le format est le suivant
data:媒体类型;base64,数据
Ici, nous devons convertir l'image en données binaires Base64, la méthode spécifique est la suivante
@Test
public void test(){
String path = "E:\\黑马\\前端\\代码\\代码\\第1章\\example4-常见元素\\heima.png";
byte[] bytes = null;
try {
Path path2 = Paths.get(path);
bytes = Files.readAllBytes(path2);
// 转换成BASE64Encoder
BASE64Encoder encoder = new BASE64Encoder();
String content = encoder.encode(bytes);
System.out.println(content);
} catch (IOException e) {
e.printStackTrace();
}
}
Les résultats de sortie sont les suivants :
L'affichage de la page est le suivant :
- URL de l'objet, doit être utilisé avec javascript
Introduit dans ce suivi js
Vidéo
<video src="文件路径"></video>
code afficher comme ci-dessous:
<!-- controls是显示播放进度条 -->
<video src="test.mp4" width="300" controls autoplay></video>
page:
l'audio
<audio src="文件路径"></audio>
code afficher comme ci-dessous:
<audio src="bgm.mp3" controls></audio>
La page est la suivante :
Voici un site recommandé, indécision MDN
MDN
3) formulaire
Fonction et grammaire
Le rôle du formulaire : collecter les données renseignées par l'utilisateur et soumettre les données au serveur
Syntaxe du formulaire
<form action="服务器地址" method="请求方式" enctype="数据格式">
<!-- 表单项 -->
<input type="submit" value="提交按钮">
</form>
- La méthode de demande de méthode a
- get (par défaut) lors de la soumission, les données suivent l'adresse URL
- Lorsque le message est soumis, les données sont dans le corps de la requête
- enctype spécifie le format de données du corps de la demande lors d'une demande de publication
- application/x-www-form-urlencoded (par défaut)
- multipart/form-data
- Les éléments de formulaire offrent une variété de façons de collecter des données
- Les données d'élément de formulaire avec un attribut de nom seront envoyées au serveur
éléments de formulaire courants
zone de texte
<input type="text" name="uesrname">
Ici, nous écrivons nous-mêmes un formulaire
<form action="https://www.baidu.com/s">
<input type="text" name="wd">
<input type="submit" value="搜索">
</form>
<hr>
La page est la suivante :
Approfondir la difficulté, combiné avec le
front end springboot :
<form action="http://localhost:8077/test">
<input type="text" name="username">
<input type="submit" name="提交">
</form>
Code principal :
@Controller
public class MyController {
@RequestMapping("/test")
@ResponseBody
public String test(String username) {
System.out.println("username:" + username);
return "收到数据";
}
}
Ici @Controller + @ResponseBody peut remplacer
la page frontale par @RestController :
Après avoir cliqué sur Soumettre, les résultats de l'opération backend sont les suivants :
boîte de mot de passe
<input type="password" name="password">
Boîte Ajouter un mot de passe
<form action="http://localhost:8077/test">
账号:<input type="text" name="username">
<hr>
密码:<input type="password" name="password">
<input type="submit" name="提交">
</form>
La page est la suivante :
cadre caché
<input type="hidden" name="id">
Il n'est pas affiché sur la page
, donc si nous voulons passer une valeur par la case cachée, ici nous pouvons attribuer une valeur à la case cachée.
<input type="hidden" name="id" value="1">
Le code de premier plan est le suivant :
<form action="http://localhost:8077/test">
账号:<input type="text" name="username">
<hr>
密码:<input type="password" name="password">
<br>
<input type="submit" name="提交">
<hr>
<input type="hidden" name="id" value="1">
</form>
Code d'arrière-plan :
@RequestMapping("/test")
public String test(User user) {
System.out.println("username:" + user.getUsername());
System.out.println("id:" + user.getId());
return "收到数据";
}
Créer une nouvelle classe d'entité
/**
* @ClassName: User
* @Description:
* @Author: wty
* @Date: 2023/7/13
*/
public class User {
private String username;
private String password;
private Integer id;
private LocalDate birthday;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public LocalDate getBirthday() {
return birthday;
}
public void setBirthday(LocalDate birthday) {
this.birthday = birthday;
}
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
", id=" + id +
", birthday=" + birthday +
'}';
}
}
Affichage des pages :
La sortie est la suivante :
boîte de date
<input type="date" name="birthday">
Ajouter des attributs en arrière-plan
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate birthday;
public LocalDate getBirthday() {
return birthday;
}
public void setBirthday(LocalDate birthday) {
this.birthday = birthday;
}
La sortie en arrière-plan est la suivante :
radio
<input type="radio" name="sex" value="男" checked>
<input type="radio" name="sex" value="女">
La page est la suivante :
<!-- 性别 -->
男<input type="radio" name="sex" value="男" checked>
女<input type="radio" name="sex" value="女">
L'attribut coché indique qu'un est sélectionné par défaut lors du processus de chargement de l'interface.
L'interface est la suivante :
la sortie en arrière-plan est la suivante :
choix multiple
<input type="checkbox" name="fav" value="唱歌">
<input type="checkbox" name="fav" value="逛街">
<input type="checkbox" name="fav" value="游戏">
Le premier plan est le suivant :
<!-- 多选 -->
唱歌<input type="checkbox" name="hobby" value="唱歌">
逛街<input type="checkbox" name="hobby" value="逛街">
游戏<input type="checkbox" name="hobby" value="游戏">
<hr>
La page est la suivante :
Le back-end est le suivant :
private List<String> hobby;
public List<String> getHobby() {
return hobby;
}
public void setHobby(List<String> hobby) {
this.hobby = hobby;
}
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
", id=" + id +
", sex='" + sex + '\'' +
", birthday=" + birthday +
", hobby=" + hobby +
'}';
}
Téléchargement de fichiers
<input type="file" name="avatar">
Remarque : Les attributs suivants doivent être ajoutés au fichier téléchargé
<form action="http://localhost:8077/test" method="post" enctype="multipart/form-data">
<!-- 文件上传 -->
<input type="file" name="avatar">
</form>
Le fond est le suivant :
private MultipartFile avatar;
@Override
public MultipartFile getAvatar() {
return avatar;
}
public void setAvatar(MultipartFile avatar) {
this.avatar = avatar;
}
public String toString() {
return "User{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
", id=" + id +
", sex='" + sex + '\'' +
", birthday=" + birthday +
", hobby=" + hobby +
", avatar=" + avatar.getSize() +
'}';
}
La sortie en arrière-plan est la suivante :
4. Requête HTTP
- La méthode de demande de méthode a
- get (par défaut) lors de la soumission, les données suivent l'adresse URL
- Lorsque le message est soumis, les données sont dans le corps de la requête
- enctype spécifie le format de données du corps de la demande lors d'une demande de publication
- application/x-www-form-urlencoded (par défaut)
- multipart/form-data
- Les éléments de formulaire offrent une variété de façons de collecter des données
- Les données d'élément de formulaire avec un attribut de nom seront envoyées au serveur
1) Demander la composition
La demande se compose de trois parties
- ligne de demande
- en-tête de requête
- corps de la demande
ligne de demande (obligatoire)
Marque rouge
Ici vous pouvez voir GET /test2?name=tony HTTP/1.1 est appelé la ligne de requête
POST est la méthode de requête
/test2?name=tony est l'URI
HTTP/1.1 est la version du protocole
en-tête de requête (obligatoire)
Marque verte
en-tête de requête :
format : nom de l'en-tête : valeur de l'en-tête
localhost : hôte virtuel
corps de la requête (facultatif)
Marquées en bleu, toutes les requêtes ne seront pas acheminées,
vous pouvez utiliser le programme telnet pour tester
2) Méthode de demande et format des données
obtenir un exemple de demande
GET /test2?name=%E5%BC%A0&age=20 HTTP/1.1
Host: localhost
- %E5%BC%A0 est le résultat encodé en URL de [Zhang]
L'arrière-plan java écrit comme ceci
@RequestMapping("/test2")
@ResponseBody
public String test2(String name) {
System.out.println("name:" + name);
return "收到:" + name;
}
Ici nous envoyons
GET /test2?name=tony HTTP/1.1
Host: localhost
Ici nous devons utiliser une machine virtuelle pour installer telnet, ici je suis CentOS, les instructions sont les suivantes :
yum install telnet -y
Après l'installation, utilisez une machine virtuelle pour vous connecter à la machine Windows
telnet ip 端口号
Entrez, après la connexion, entrez
GET /test2?name=tony HTTP/1.1
Host: localhost
Après avoir appuyé deux fois sur Entrée, le résultat est renvoyé :
exemple de demande de publication
POST /test2 HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded
Content-Length: 21
name=%E5%BC%A0&age=18
détails du format application/x-www-form-urlencoed :
- Les paramètres sont divisés en noms et valeurs, séparés par =
- Plusieurs paramètres sont séparés par &
- [Zhang] et d'autres caractères spéciaux doivent être encodés en [%E5%BC%A0] avec encodeURIComponent() avant l'envoi
Ici on le teste, la requête est la suivante :
POST /test2 HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded
Content-Length: 10
name=zhang
Ici Content-Length = 10 n'est pas défini par hasard. Selon name=zhang, un caractère anglais occupe une longueur, un total de 10 octets.
Linux a reçu la réponse
plusieurs paramètres
Demande de publication avec plusieurs paramètres
S'il y a plusieurs paramètres, ici on modifie le code du backend Java
@RequestMapping("/test22")
@ResponseBody
public String test22(String name, Integer age) {
System.out.println("name:" + name + ",age:" + age);
return "收到name:" + name + ",age:" + age;
}
Le test telnet est le suivant :
POST /test22 HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded
Content-Length: 16
name=Lucy&age=18
Le résultat est le suivant :
Quelle est la longueur du contenu ici ? Nous pouvons simplement apprendre javascript
pour ouvrir le navigateur et entrer F12 dans la console :
"name=Lucy&age=18".length
Après le retour chariot,
16 voici la valeur de Content-Length.
Obtenir une requête avec plusieurs paramètres
Ici, nous essayons à nouveau d'obtenir une situation multi-paramètres de requête
GET /test22?name=tony&age=20 HTTP/1.1
Host: localhost
revient comme suit :
Envoyer des caractères chinois
Appuyez sur F12 dans le navigateur pour ouvrir la console
encodeURIComponent("张")
Après le retour chariot, l'encodage des caractères chinois sort
'%E5%BC%A0'
Envoyons une autre requête GET
GET /test22?name=%E5%BC%A0&age=20 HTTP/1.1
Host: localhost
J'ai reçu le résultat :
comment le caractère chinois "Zhang" est-il devenu un code URL ? Faisons des recherches.
En d'autres termes, d'où vient %E5%BC%A0.
Nous pourrions tout aussi bien utiliser d'abord le code Java pour convertir "Zhang" dans le format UTF-8 correspondant
@Test
public void test() throws Exception {
// utf-8
byte[] bytes = "张".getBytes(StandardCharsets.UTF_8);
System.out.println(bytes);
for (byte b : bytes) {
System.out.println(Integer.toHexString(Byte.toUnsignedInt(b)));
}
}
Résultat de sortie :
[B@50de0926
e5
bc
a0
exemple de requête json
POST /test3 HTTP/1.1
Host: localhost
Content-Type: application/json
Content-Length: 25
{"name":"zhang","age":18}
format d'objet json
{"属性名":属性值}
où les valeurs d'attribut peuvent être
- chaîne ""
- nombre
- vrai faux
- nul
- objet
- déployer
format de tableau json
[元素1, 元素2, ...]
Nous envoyons comme suit :
POST /test3 HTTP/1.1
Host: localhost
Content-Type: application/json
Content-Length: 25
{"name":"zhang","age":18}
Créer une nouvelle classe d'entité dans l'arrière-plan Java
package com.itheima.pojo;
/**
* @ClassName: Req
* @Description:
* @Author: wty
* @Date: 2023/7/13
*/
public class Req {
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Req{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
Le Controller est le suivant :
Notez ici que l'annotation @RequestBody doit être ajoutée pour recevoir des données au format json.
@RequestMapping("/test3")
@ResponseBody
public Req test3(@RequestBody Req req) {
System.out.println(req);
return req;
}
Le retour est le suivant :
19 et 0 sont ici envoyés par blocs, et le nombre final de caractères est 0, donc l'envoi est stoppé.
Lors de l'envoi ici, Content-Length : 25.
Comment peut-il devenir 19 alors qu'il est évidemment de 25 lors de la réception ?
La sortie d'arrière-plan Java est la suivante :
s'il s'agit de JDK16, vous pouvez également utiliser Req pour remplacer la classe d'entité, mais Req est équivalent à get, qui ne changera pas après l'affectation initiale, et n'a pas de méthode set, qui est un immuable objet.
@RequestMapping("/test3")
public Req test3(@RequestBody Req req) {
System.out.println(req);
return req;
}
record Req(String name,Integer age){
}
Avis:Les caractères chinois json peuvent être envoyés comme d'habitude
Ouvrez le navigateur et entrez F12, puis entrez
'{"name":"张","age":18}'.length
Renvoie : 21 (caractères)
Parce que le transfert est basé sur des octets, en UTF-8, un caractère chinois est de trois octets, donc
21 -1 + 3 = 23
donc Content-Length est 23
POST /test3 HTTP/1.1
Host: localhost
Content-Type: application/json
Content-Length: 23
{"name":"张","age":18}
Le résultat est le suivant :
exemple de requête en plusieurs parties
POST /test22 HTTP/1.1
Host: localhost
Content-Type: multipart/form-data; boundary=123
Content-Length: 125
--123
Content-Disposition: form-data; name="name"
lisi
--123
Content-Disposition: form-data; name="age"
30
--123--
- bound=123 est utilisé pour définir le séparateur
- Le délimiteur de départ est
--分隔符
- Le délimiteur de fin est
--分隔符--
Le backend Java est le suivant :
@RequestMapping("/test22")
@ResponseBody
public String test22(String name, Integer age) {
System.out.println("name:" + name + ",age:" + age);
return "收到name:" + name + ",age:" + age;
}
Les résultats telnet sont les suivants :
Voici une question sur
la façon dont Content-Length : 125 est calculé
·--123
Content-Disposition: form-data; name="name"
lisi
--123
Content-Disposition: form-data; name="age"
30
--123--·.length
Les backticks sont introduits ici, et la réponse finale est
que 116 116 est 9 octets de moins que 125, alors quelle est la différence entre ces 9 octets ? La différence est le saut de ligne.
Il y a en fait deux symboles \r et \n dans le saut de ligne, mais un seul est compté en JavaScript, et nos données multilignes sont exactement 9 lignes, nous devons donc ajouter 9
Résumé du format des données
Le client envoie
- codage
- application/x-www-form-urlencoded : url-encoded
- application/json : encodage utf-8
- multipart/form-data : l'encodage de chaque partie peut être différent
- Les formulaires ne prennent en charge que l'envoi de données aux formats application/x-www-form-urlencoded et multipart/form-data
- Le téléchargement de fichier doit utiliser le format multipart/form-data
- le code js peut prendre en charge l'envoi de données dans n'importe quel format
serveur recevoir
- Pour les données aux formats application/x-www-form-urlencoded et multipart/form-data, Spring les reçoit de la même manière et n'a besoin d'utiliser que le nom de propriété du bean java pour correspondre au nom du paramètre de requête.
- Pour les données au format applicaiton/json, Spring doit utiliser l'annotation @RequestBody + bean java pour recevoir les données
3) principe de séance
Http est sans état et a des sessions
- Sans état signifie que les requêtes sont indépendantes les unes des autres, les données demandées pour la première fois ne peuvent pas être réutilisées pour la deuxième requête
- Avoir une session signifie que le client et le serveur ont des technologies correspondantes qui peuvent temporairement stocker des données et permettre le partage des données entre les requêtes
Le serveur utilise la technologie de session pour stocker temporairement les données
en direct
GET /s1?name=zhang HTTP/1.1
Host: localhost
Le backend Java est le suivant :
@RequestMapping("/s1")
@ResponseBody
public String s1(HttpSession session, String name) {
session.setAttribute("name", name);
return "数据已存储";
}
Les données renvoyées sont les suivantes :
jsessionid = 5EC247CB0B301ACBFE90157D6F723CC5
Prendre
GET /s2 HTTP/1.1
Host: localhost
Cookie: JSESSIONID=5EC247CB0B301ACBFE90157D6F723CC5
Le code Java principal est le suivant :
@RequestMapping("/s2")
@ResponseBody
public String s2(HttpSession session) {
return "取出数据" + session.getAttribute("name");
}
La sortie est la suivante :
technologie de session pour l'authentification
Inconvénients : il ne convient pas aux projets distribués, car les projets distribués ont plusieurs serveurs, et il est évidemment déraisonnable de stocker une session complète dans chaque serveur, et la technologie jwt est introduite ici.
4) principe jwt
technologie jwt pour l'authentification
générer un jeton
GET /j1?name=zhang&pass=123 HTTP/1.1
Host: localhost
jeton为
eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ6aGFuZyJ9.qmta3qjU3XKd8di9n6h9DhbTznJYb75v0CESA7ZLx0E
Code Java principal
@RequestMapping("/j1")
@ResponseBody
public String j1(String name, String pass) {
if (!StringUtils.isEmpty(name) && !StringUtils.isEmpty(pass)) {
if ("zhang".equals(name) && "123".equals(pass)) {
String token = Jwts.builder().setSubject(name).signWith(key).compact();
return "验证身份通过:" + token;
} else {
return "验证身份失败";
}
}
return "用户名或者密码为空,验证身份失败";
}
vérifier le jeton
GET /j2 HTTP/1.1
Host: localhost
Authorization: eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ6aGFuZyJ9.qmta3qjU3XKd8di9n6h9DhbTznJYb75v0CESA7ZLx0E
Code Java principal
@RequestMapping("/j2")
@ResponseBody
public String j2(@RequestHeader String authorization) {
try {
System.out.println(authorization);
Jws<Claims> jws = Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(authorization);
return "校验通过, 你是:" + jws.getBody().getSubject();
} catch (Exception e) {
return "校验失败";
}
}
La sortie est la suivante :
Voici une question, à quoi sert cette longue chaîne de jetons, ici nous écrivons une méthode dans IDEA
@Test
public void test() {
// header(签名算法) payload(数据) 签名
// eyJzdWIiOiJhZG1pbiJ9
// token分成了3个部分,每个部分由.进行分割
// 第一个部分 eyJhbGciOiJIUzI1NiJ9 header(签名算法)未加密
// 第二个部分 eyJzdWIiOiJ6aGFuZyJ9 payload(数据)未加密
// 第三个部分 qmta3qjU3XKd8di9n6h9DhbTznJYb75v0CESA7ZLx0E 签名 加密
String token = "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ6aGFuZyJ9.qmta3qjU3XKd8di9n6h9DhbTznJYb75v0CESA7ZLx0E";
// 1 2 3 ==> 6
// 1 4 3 ==> 8
// 第一个部分
System.out.println(new String(Base64.getDecoder().decode("eyJhbGciOiJIUzI1NiJ9")));
// 第二个部分
System.out.println(new String(Base64.getDecoder().decode("eyJzdWIiOiJ6aGFuZyJ9")));
// 第三个部分
// admin 权限大的用户 可以做所有的操作
//String str = "{\"sub\":\"zhang\"}";
// eyJzdWIiOiJ6aGFuZyJ9
String str = "{\"sub\":\"admin\"}";
// eyJzdWIiOiJhZG1pbiJ9
System.out.println(Base64.getEncoder().encodeToString(str.getBytes(StandardCharsets.UTF_8)));
}
Remplaçons le nom de l'autorisation au milieu
par celui de l'utilisateur admin
GET /j2 HTTP/1.1
Host: localhost
Authorization: eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbiJ9.qmta3qjU3XKd8di9n6h9DhbTznJYb75v0CESA7ZLx0E
Nous avons visité et essayé, et avons constaté
que le serveur n'était pas trompé, alors pourquoi le serveur peut vérifier le problème, principalement dans la troisième partie de la signature, la signature est basée sur les deux premières parties pour générer la clé secrète.
//
// 1 2 3 ==> 6
// 1 4 3 ==> 8
5. CSS
C'est-à-dire les feuilles de style en cascade, qui décrivent les performances et l'effet d'affichage des pages Web
1) sélecteur
sélecteur de type - correspondance par nom de balise (sélecteur d'élément)
Créer un nouveau fichier style-exercise.css
p {
background-color: blueviolet;
}
html plus le code suivant
<link rel="stylesheet" href="style-exercise.css">
L'effet est le suivant : la couleur d'arrière-plan de l'étiquette de paragraphe devient violette
sélecteur de classe - correspond à l'attribut de classe de l'élément
Modifier certaines balises qui doivent être modifiées en html
<body>
<p id="p1">1111111111111</p>
<p id="p2" class="c2">2222222222222</p>
<p id="p3" class="c3">3333333333333</p>
</body>
Modifier style-exercise.css
/* class选择器 */
.c2 {
background-color: brown;
}
.c3 {
background-color: chartreuse;
}
L'effet est le suivant :
id selector - correspond à l'attribut id d'un élément
modifier le fichier html
<body>
<p id="p1">1111111111111</p>
<p id="p2">2222222222222</p>
<p id="p3">3333333333333</p>
</body>
Modifier style-exercise.css
/* id选择器 */
#p1 {
background-color: cornflowerblue;
}
L'effet est le suivant :
ici, nous ne pouvons pas nous empêcher de demander, si plusieurs sélecteurs correspondent au même élément, quelle est la priorité ?
Le code css est le suivant :
/* 元素选择器-type */
p {
background-color: blueviolet;
}
/* class选择器 */
.c2 {
background-color: brown;
}
/* id选择器 */
#p2 {
background-color: cornflowerblue;
}
Nous modifions tous le style du paragraphe 2.
L'effet final est le suivant :
Conclusion :
sélecteur d'identifiant > sélecteur de classe > sélecteur de sélection
2) Attributs et valeurs
- couleur de fond : rouge ;
- …
- afficher
Voir
la requête de style CSS pour plus de détails
Voici une brève explication de l'attribut display.
Le code est le suivant :
#p2 {
background-color: cornflowerblue;
display: none;
}
La page est la suivante : trouvé que p2 est masqué
s'il est remplacé par
/* id选择器 */
#p2 {
background-color: cornflowerblue;
display: block;
}
Lorsque p2 est trouvé, il s'affiche.
3) Mise en page
éléments html liés à la mise en page
div
L'interface fournie par les données est la suivante :
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>布局</title>
<style>
html,body {
margin:0;
width: 100%;
height: 100%;
text-align: center;
font-size: 30px;
font-weight: bold;
}
div{
box-sizing: border-box;
}
.container {
height: 100%;
position: relative;
}
#header {
background-color:rgb(152, 152, 255);
width: 100%;
height: 80px;
padding-top: 10px;
}
#aside {
background-color:aquamarine;
float: left;
width: 200px;
height: calc(100% - 140px);
padding-top: 10px;
}
#main {
background-color:honeydew;
float: left;
width: calc(100% - 200px);
height: calc(100% - 140px);
padding-top: 10px;
padding-left: 20px;
text-align: left;
}
#footer {
background-color:darksalmon;
height: 60px;
padding-top: 10px;
}
</style>
</head>
<body>
<div class="container">
<div id="header">#header</div>
<div id="aside">#aside</div>
<div id="main">#main</div>
<div style="clear: both;"></div>
<div id="footer">#footer</div>
</div>
</body>
</html>
L'effet est comme indiqué sur la figure :
ici, le style peut être compris comme un style interne . Avant de créer un nouveau css et de l'importer via un lien, cela s'appelle un style externe .
Nous ajoutons du texte de type type à div id = "main"
<body>
<div class="container">
<div id="header">#header</div>
<div id="aside">#aside</div>
<div id="main">
#main
<form action="">
<input type="text" value="文本">
</form>
</div>
<div style="clear: both;"></div>
<div id="footer">#footer</div>
</div>
</body>
Le style est le suivant : Texte ajouté
modèle
Regardez d'abord le code source des données
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>模板</title>
<style>
html,
body {
margin: 0;
width: 100%;
height: 100%;
}
.btn {
padding: 10px;
}
.out {
width: 100%;
height: 100%;
box-sizing: border-box;
background-color:darkgrey;
}
.in {
width: 200px;
box-sizing: border-box;
height: 200px;
border: solid 2px black;
padding: 10px;
background-color: antiquewhite;
margin: 10px;
float: left;
}
</style>
</head>
<body>
<div class="out">
<div class="btn">
<input type="button" value="根据模板创建" id="add">
</div>
</div>
<template id="t">
<div class="in">
<form action="">
<p><label>姓名</label> <input type="text"></p>
<p><label>年龄</label> <input type="text"></p>
<p><input type="submit" value="添加"></p>
</form>
</div>
</template>
<script>
document.getElementById("add").onclick = () => {
let t = document.getElementById("t");
let inputs = t.content.querySelectorAll("input");
inputs[0].value = randomGenerator("abcdefghijklmnopqrstuvwxyz", 5);
inputs[1].value = randomGenerator("1234567890", 2);
const c = document.importNode(t.content, true);
document.querySelector(".out").appendChild(c);
}
function randomGenerator(str, n) {
const result = [];
for (let i = 0; i < n; i++) {
result.push(str.charAt(Math.floor(Math.random() * str.length)))
}
return result.join("");
}
</script>
</body>
</html>
L'effet est le suivant : après avoir cliqué sur le modèle,
le nom et l'âge sont ajoutés dynamiquement à la mise en page via JavaScript