Connaissances frontales que les programmeurs Java doivent maîtriser (1)

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.

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

insérez la description de l'image ici

Objectifs du cours

insérez la description de l'image ici

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
insérez la description de l'image ici
Cliquez sur la page 2
insérez la description de l'image ici

cliquez page 3
insérez la description de l'image ici

Alors, qu'est-ce que le langage de balisage ?
Faisons un clic droit et ouvrons-le avec VS Code.
insérez la description de l'image ici
Ces parties entre crochets sont appelées Markup. Dans le front-end, nous les appelons des onglets.
insérez la description de l'image ici

  • 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.
insérez la description de l'image ici
Vous pouvez voir que la police et la couleur d'arrière-plan du lien hypertexte ont changé.
insérez la description de l'image ici

1. Éléments HTML

HTML elementsse 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.
insérez la description de l'image ici
Le code est le suivant :

<p>Hello, world!</p>

Ouvrir avec un navigateur
insérez la description de l'image ici
L'effet est le suivant :
insérez la description de l'image ici
Si nous voulons augmenter le nombre d'étiquettes, copiez
ALT + SHIFT + ↓ via les touches de raccourci
insérez la description de l'image ici
pour afficher les résultats comme suit :
insérez la description de l'image ici
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
insérez la description de l'image ici

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
    insérez la description de l'image ici
    . 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
insérez la description de l'image ici

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>

insérez la description de l'image ici

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

insérez la description de l'image ici

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

insérez la description de l'image ici

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>测试页面</title>
  </head>
  <body>
    <p id="p1">Hello, world!</p>
    <img src="1.png">
  </body>
</html>
  • htmlL'é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 racine
  • headLes éléments incluent des éléments qui ne sont pas utilisés pour afficher le contenu, tels que title, link, meta(指定编码)etc.
  • bodyLes é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
insérez la description de l'image ici
Shortcut key!, vous pouvez directement générer le modèle html
insérez la description de l'image ici
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 :
insérez la description de l'image ici

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 :
insérez la description de l'image ici

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 :
insérez la description de l'image ici

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:
insérez la description de l'image ici

Liste

liste non ordonnée liste non ordonnée

<ul>
    <li>列表项1</li>
    <li>列表项2</li>
    <li>列表项3</li>
</ul>

insérez la description de l'image ici

liste
ordonnée liste ordonnée

<ol>
    <li>列表项1</li>
    <li>列表项2</li>
    <li>列表项3</li>
</ol>

insérez la description de l'image ici

liste à plusieurs niveaux

<ul>
    <li>
    	北京市
        <ul>
            <li>海淀区</li>
            <li>朝阳区</li>
            <li>昌平区</li>
        </ul>
    </li>
    <li>
    	河北省
        <ul>
            <li>石家庄</li>
            <li>保定</li>
        </ul>
    </li>
</ul>

insérez la description de l'image ici

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>

insérez la description de l'image ici

(2) Accéder aux pages Internet
<a href="http://www.baidu.com">互联网网页</a>

insérez la description de l'image ici

après clic
insérez la description de l'image ici

(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>

insérez la description de l'image ici
Après avoir cliqué, allez à la position de l'étiquette où se trouve p1
insérez la description de l'image ici

2) Multimédia

Image

<img src="文件路径">

Il existe 3 formats src

  • adresse de fichier

Par exemple

<img src="heima.png">

insérez la description de l'image ici

  • 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 :
insérez la description de l'image ici
L'affichage de la page est le suivant :
insérez la description de l'image ici

  • 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:
insérez la description de l'image ici

l'audio

<audio src="文件路径"></audio>

code afficher comme ci-dessous:

<audio src="bgm.mp3" controls></audio>

La page est la suivante :

insérez la description de l'image ici
Voici un site recommandé, indécision MDN
MDN
insérez la description de l'image ici

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 :
insérez la description de l'image ici

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 :
insérez la description de l'image ici

Après avoir cliqué sur Soumettre, les résultats de l'opération backend sont les suivants :
insérez la description de l'image ici

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 :
insérez la description de l'image ici

cadre caché
<input type="hidden" name="id">

Il n'est pas affiché sur la page
insérez la description de l'image ici
, 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 :
insérez la description de l'image ici

La sortie est la suivante :
insérez la description de l'image ici

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;
    }

insérez la description de l'image ici
La sortie en arrière-plan est la suivante :
insérez la description de l'image ici

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 :
insérez la description de l'image ici
la sortie en arrière-plan est la suivante :
insérez la description de l'image ici

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 :
insérez la description de l'image ici

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 +
                '}';
    }

insérez la description de l'image ici

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>

insérez la description de l'image ici
insérez la description de l'image ici

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 :
insérez la description de l'image ici

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

  1. ligne de demande
  2. en-tête de requête
  3. corps de la demande

ligne de demande (obligatoire)

Marque rouge
insérez la description de l'image ici
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
insérez la description de l'image ici
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,
insérez la description de l'image ici
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é :
insérez la description de l'image ici

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
insérez la description de l'image ici

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 :
insérez la description de l'image ici
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,
insérez la description de l'image ici
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 :
insérez la description de l'image ici

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 :
insérez la description de l'image ici
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 :
insérez la description de l'image ici
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 :
insérez la description de l'image ici
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 :
insérez la description de l'image ici

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 :
insérez la description de l'image ici
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
insérez la description de l'image ici
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 :
insérez la description de l'image ici
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 :
insérez la description de l'image ici

technologie de session pour l'authentification

Client LoginController LoginInterceptor Session 登录请求 检查用户名,密码,验证通过 存入用户名 登录成功 其它请求 获取用户名 用户名存在,放行 Client LoginController LoginInterceptor Session

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

Client LoginController LoginInterceptor 登录请求 检查用户名,密码,验证通过 登录成功,返回token 其它请求,携带token 校验token,校验无误,放行 Client LoginController LoginInterceptor

générer un jeton

GET /j1?name=zhang&pass=123 HTTP/1.1
Host: localhost

insérez la description de l'image ici
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 :
insérez la description de l'image ici

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é
insérez la description de l'image ici
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
insérez la description de l'image ici

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 :
insérez la description de l'image ici

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 :
insérez la description de l'image ici
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 :
insérez la description de l'image ici
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é
insérez la description de l'image ici
s'il est remplacé par

/* id选择器 */
#p2 {
    
    
    background-color: cornflowerblue;
    display: block;
}

Lorsque p2 est trouvé, il s'affiche.
insérez la description de l'image ici

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 :
insérez la description de l'image ici
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é
insérez la description de l'image ici

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,
insérez la description de l'image ici
le nom et l'âge sont ajoutés dynamiquement à la mise en page via JavaScript
insérez la description de l'image ici

Je suppose que tu aimes

Origine blog.csdn.net/sinat_38316216/article/details/131658170
conseillé
Classement