[TOC]

第一章HTML

一、 网页的构成

1.1 网页

浏览器中显示的内容,浏览器是网页的展示器。编写好的网页,放在浏览器中即可运行。编写网页我们使用的就是HTML语言。

1.2 网页的构成

摘要 说明
结构(HTML) HTML是网页内容的载体。内容就是网页制作者放在页面上想要让用户浏览的信息,可以包含文字、图片、视频等。
表现(CSS) CSS样式是表现。就像网页的外衣。比如,标题字体、颜色变化,或为标题加入背景图片、边框等。所有这些用来改变内容外观的东西称之为表现。
行为(JavaScript / jQuery) JavaScript是用来实现网页上的特效效果。如:鼠标滑过弹出下拉菜单。或鼠标滑过表格的背景颜色改变。还有购物网站中图片的轮换。可以这么理解,有动画的,有交互的一般都是用JavaScript来实现的

二、 HTML简介

  • HTML 是用来描述网页的一种语言。
  • HTML 指的是超文本标记语言 (Hyper Text Markup Language)
  • 超文本就是指页面内可以包含图片、链接,甚至音乐、程序等非文字元素
  • HTML 不是一种编程语言,而是一种标记语言 (markup language)
  • 标记语言是一套标记标签 (markup tag),由一组<>包围的关键字
  • HTML网页的后缀名一般为.html
  • HTML 使用标记标签来描述网页

JavaWEB葵花宝典 - 图1

  • HTML文件的基本结构
    • 为HTML页面中的根标签,所有的HTML网页中的标签都在中。
    • 这里标签用于定义文档的头部,它是所有头部元素的容器。头部元素有、、、 等标签。
    • 在和标签之间的内容是网页的主要内容,如、、、等网页内容标签,在这里的标签中的内容会在浏览器中显示出来。

三、 HTML语法

  • 标签的语法
    • 标签由英文尖括号 < 和 > 括起来,如:
    • html中的标签一般都是成对出现的,分开始标签和结束标签。结束标签比开始标签多一个 / ,..;还有一些是自结束标签,如:
    • 标签与标签之间是可以嵌套的,但先后顺序必须保持一致,如:里嵌套,那么必须放在的前面。如: ..
    • 注释是不可以嵌套的,如: —>
    • HTML标签不区分大小写,和是一样的,但万维网联盟(W3C)建议小写。
  • 元素模型
  • JavaWEB葵花宝典 - 图2

四、 HTML的常用标签

4.1 标题标签






  • 默认占用浏览器的一整行,并且前后要空一行

4.2 段落标签

两个黄鹂鸣翠柳


是否还没女朋友

  • 段落标签也会独占浏览器的一行,而且前后还会空出一行。
  • 使用空的段落标记

    去插入一个空行是个坏习惯。用
    标签代替它!

4.3 换行标签


:是个自结束标签


4.4 无序列表



  • 网页

  • 新闻

  • 视频

  • 贴吧


4.5有序列表


  1. 单身久了,坐地铁女孩蹭下肩膀,你连你们的孩子叫什么名字都想好了

  2. 太久没接吻,吃个鸭舌都能感到温柔

  3. 太久没牵手,拿着泡椒凤爪心都会颤抖


4.6 图片标签

<img alt=”“ src=”” title=””/>

  • alt:图片无法显示时显示的描述性文字
  • src:图片的地址(或路径)。这里分为相对路径和绝对路径。
  • width和height:设置图片的宽度和高度

使用相对路径查找目标资源心得

  • 目标文件与当前文件在同一目录下,直接查找使用。
  • 目标文件与当前文件不在同一目录下,先找目标文件父包,再找目标文件
    • 如:父包也不与当前文件在同包下,将父包当成目标文件,继续找父包的父包。以此类推,找到WebContent根目录为止。

补充内容:html中的相对路径与绝对路径
相对路径:以当前文件所在的路径为基准
. 表示当前文件所在目录
.. 表示上一级目录
资源名 表示当前目录下的资源 ./资源名 ./可以省略
使用../返回上一级

绝对路径:
盘符:\文件名 =====>>>> 错误(真实路径)
http://ip:port/工程名/资源名 ===>>> 正确
比如:http://localhost:8080/img/13.jpg

4.7 超链接

  • href:指向一个链接地址
  • target:定义被链接的文档在何处显示。
    • 值为”_self”时在向当前窗口打开新的网页(默认)
    • 值为”_blank”时在新的窗口打开

4.8 转义字符

  • 当显示页面时,浏览器会移除源代码中多余的空格和空行。所有连续的空格或空行都会被算作一个空格。即,HTML 代码中的所有连续的空行(换行)也被显示为一个空格。
  • 在 HTML 中不能使用小于号(<)和大于号(>),这是因为浏览器会误认为它们是标签。
  • 如果想表示多个空格,需要使用如下的转义字符。

JavaWEB葵花宝典 - 图3

说明1:如需显示小于号,我们必须这样写:< 或 <
说明2:使用实体名而不是数字的好处是,名称易于记忆。不过坏处是,浏览器也许并不支持所有实体名称(对实体数字的支持却很好)。

4.9 div标签

  • div是html中最灵活最重要的元素,div就像一个容器,里面可以装很多内容。本身没有特殊的语义。
  • 它是块级元素,会占用网页的一行。
  • Div的主要作用:可以通过调整自己的样式来完成网页的复杂布局
  • 它可以把一些独立的逻辑部分(如网页中独立的栏目版块)划分出来

补充说明:
块级元素:各占据一行,垂直方向排列。块级元素从新行开始结束接着一个断行。width、height、padding、margin有效。
内联元素:在一条直线上排列,都是同一行的,水平方向排列。设置width、height、padding、margin无效。

五、 HTML中的表格

5.1 HTML中的表格































其中: - 标记这是一个表格 - 表示表格的一行 -
表示表格的一列 - 跨列合并单元格用 colspan 属性 - 跨行合并单元格用 rowspan 属性 - 常用属性 - border :设置表格边框 - width:设置表格的宽度,单位px - height:设置表格的高度,单位px - align:设置表格的对齐方式 举例:
JavaWEB葵花宝典 - 图4 ## 六、 HTML中的表单 ### 6.1 生活中的表单 表单类似生活中的单据,票据,申请表之类的东西,生活中我们经常会填写很多表单,比如入职申请表,入学登记表,员工信息表等。
JavaWEB葵花宝典 - 图5 JavaWEB葵花宝典 - 图6 ### 6.2 表单中的常用标签 #### 1. 表单标签
- action表示表单填写完成要提交给的地方。就像我们把入职申请表填写完成后要交给部门经理一样。 - 提交的方式分为:get 或 post - get:是将所有的提交的数据显示在地址栏,长度会有一些限制 - post:将要提交的数据放在请求体中,在url表单里面没有任何数据 #### 2. 文本输入框
#### 3. 密码输入框
#### 4. 单选框
性别:


#### 5. 复选框

你的爱好:
篮球
足球
乒乓球

6. 下拉列表


#### 7. 重置按钮
#### 8. 提交按钮
#### 9. 普通按钮
# 第二章 CSS HTML页面实在太丑了,怎么破?!
## 一、 CSS简介 CSS全称为“层叠样式表 (Cascading Style Sheets)”,它主要是用于定义HTML元素(或内容)在浏览器内的显示样式,如文字大小、颜色、字体、边框、位置等。
## 二、 CSS基本语法 ### 2.1 基本格式 - CSS样式由选择符(选择器)和声明组成,而声明又由属性和值组成,如下图所示: JavaWEB葵花宝典 - 图7 JavaWEB葵花宝典 - 图8 - 格式为: 选择器 {
样式名:样式值;
样式名:样式值;
…………
}
### 2.2 语法说明 - 属性 (property) 是你希望改变的属性,并且每个属性都有一个值。属性和值被冒号分开,并由花括号包围,这样就组成了一个完整的样式声明(declaration),例如:p {color: blue} - 多个声明:如果要定义不止一个声明,则需要用英文分号”;”将每个声明分开。虽然最后一条声明的最后可以不加分号,但尽量在每条声明的末尾都加上分号 - 每行最好只描述一个属性 - CSS对大小写不敏感,但建议使用小写。不过存在一个例外:class 和 id 名称对大小写是敏感的。 - CSS注释:/注释内容/ ### 2.3 CSS样式编写位置 方式一:写在标签的style属性中:

字体大小用px表示


落霞与孤鹜齐飞


方式二:写在html头的style标签中(style标签一般写在head标签与title标签之间):

方式三:写在外部的css文件中,然后通过link标签引入外部的css文件

其中,style.css定义如下:
@charset “UTF-8”;
/ 这是css与html结合使用的第三种方式 /
div {
border: 1px solid red;
}
span {
border: 1px solid green;
}
说明:当同一个 HTML 元素被不止一个样式定义时,会使用哪个样式呢?
优先级按照上述讲的三种方式依次降低。内联样式(在 HTML 元素内部)拥有最高的优先权。
## 三、 选择器的分类 选择器:浏览器根据“选择器”确定受CSS样式影响的HTML元素。
### 分类1:标签选择器 按照标签名选中相应的元素。如上图的p。
p {
color:red;
}
### 分类2:类选择器 按照元素的类名选中相应的元素,使用.class值
.class属性值{ }
举例:

青春正好


编程趁早 .foot {
color:red;
}
### 分类3:ID选择器 按照元素的id选中相应的元素,使用#id值
#id属性值{ }
举例:

大家好

#abc {
color:red;
}
# 第三章 JavaScript ## 一、 JavaScript起源 ### 1.1 起源 - N年前 - 拨号上网,网速很慢,数据提交到服务器端验证,体验很差 - 于是,就有人在想:能不能让这些数据在浏览器端验证呢? - 20世纪90年代 - 1995年,由Netscape公司的Brendan Eich,在网景导航者浏览器上首次设计实现而成。Netscape在最初将其脚本语言命名为LiveScript。 - 后来Netscape与Sun合作,网景公司管理层希望它外观看起来像Java,因此取名为JavaScript。 - JavaScript是一门客户端脚本语言,主要运行在浏览器中,浏览器中负责运行JavaScript脚本代码的程序叫JavaScript引擎。 - 五彩缤纷的现在 - 时至今日JavaScript已经不仅仅局限于表单验证,网页上很多炫丽动感的特效都有它的功劳 ### 1.2 Java与JavaScript的关系 没有关系,只是语法类似!
### 1.3 特性 ##### ① 脚本语言 JavaScript是一种解释型的脚本语言。不同于C、C++、Java等语言先编译后执行, JavaScript不会产生编译出来的字节码文件,而是在程序的运行过程中对源文件逐行进行解释。
##### ② 基于对象 JavaScript是一种基于对象的脚本语言,它不仅可以创建对象,也能使用现有的对象。但是面向对象的三大特性:『封装』、『继承』、『多态』中,JavaScript能够实现封装,可以模拟继承,不支持多态,所以它不是一门面向对象的编程语言。
##### ③ 弱类型 JavaScript中也有明确的数据类型,但是声明一个变量后它可以接收任何类型的数据,并且会在程序执行过程中根据上下文自动转换类型。
##### ④ 事件驱动 JavaScript是一种采用事件驱动的脚本语言,它不需要经过Web服务器就可以对用户的输入做出响应。
##### ⑤ 跨平台性 JavaScript脚本语言不依赖于操作系统,仅需要浏览器的支持。因此一个JavaScript脚本在编写后可以带到任意机器上使用,前提是机器上的浏览器支持JavaScript脚本语言。目前JavaScript已被大多数的浏览器所支持。
### 1.4 HelloWorld JavaWEB葵花宝典 - 图9 对应的代码实现如下:







## 二、基本语法 JavaScript需要包括在
说明:一般声明在head标签中,与style标签有点像。 - 方式二:写在外部的.js文件中。然后通过script标签的src属性引入。 - 这里的文件路径,可以是相对路径,也可以是绝对路径。
说明:type属性 :默认值 text/javascript可以不写,不写也是这个值。
src属性:当需要引入一个外部的js文件时,使用该属性指向文件的地址。
特别注意:方式一和方式二不要同时使用。一旦同时使用,会默认执行方式二中js文件中的js代码。
### 2.2 变量 #### 2.2.1 JavaScript的数据类型 - 基本数据类型 - 数值类型:number - 字符串类型:string - 布尔类型:boolean - 其他值与boolean的转换规则: - 0、null、undefined、“”(空串)在运算时,都认为是false - undefined型(Undefined) - 对象类型: - 函数对象:Function - 数组对象:Array - 使用typeof 判断,结果是Object - 一般对象:Object #### 2.2.2 变量的声明 - 使用var定义即可。比如:var num = 65; var name = “马大云”; - 变量声明时不需要指定类型,可以接受所有的数据类型。 #### 2.2.3 变量的赋值 - 变量在赋值过程中可以接受不同类型的值。比如:var x = 123; x = “atguigu.com”; - 没有赋值的变量,默认为undefined - 使用typeof(变量名),判断变量的类型 - JS中每一条语句以分号(;)结尾。如果不写分号,浏览器会自动添加,但是会消耗一些系统资源。 ### 2.3 数组 #### 2.3.1 数组的定义 - 定义一个空数组:var arr = [] 或 var arr=new Array(); - 定义一个非空数组:var arr1 = [“Tom”,”atguigu.com”,true]; #### 2.3.2 数组的调用 - 数组的角标是从0开始的,直接通过角标进行调用。比如: alert(arr[0]); #### 2.3.3 数组的遍历 var arr = [10,20];
for(var i = 0;i < arr.length;i++){
alert(arr[i]);
}
### 2.4 函数 #### 2.4.1 函数声明与调用 - 使用function关键字 - 不需要指定返回值。如果函数有返回值,只需要在函数体内直接使用return语句返回需要的值即可。 - 不需要指定形参类型(因为js所有类型都使用var来声明) - 函数在js中也是一种对象,可以将函数的引用赋值给变量 - 方式一: - 声明格式: - function 函数名(形参列表){
函数体
} - 举例: - function sum(n, m) {
return n + m;
} - 调用:函数名(参数)。 - var result = sum(1,2);
alert(result);//3 - 方式二:匿名函数 - 声明格式: - var 变量名 = function(形参列表){
函数体;
} - 举例1: - var add = function(a,b){
return a+b;
} - 举例2: - var info = function(){
alert(“美好的事情即将发生“);
} - 调用:变量名(实参值) - var result = add(1,2);
alert(result); info(); ### 2.5 对象 #### 2.5.1 对象的创建与调用 - 方式一:使用new Object()创建 - 格式 - var 变量名 = new Object();//创建一个空的对象实例
变量名.属性名 = 值;//给创建的对象添加一个属性
变量名.函数名 = function(){}; //给创建的对象添加一个函数 - 对象的访问(即:属性或函数的调用) - 变量名.属性;
变量名.函数名(); - 举例 - //对象的定义
var obj = new Object();
alert(typeof(obj)); //声明属性和函数
obj.name = “Tom”;
obj.study = function() {
alert(“好好学习,天天向上”);
}; //调用属性
alert(obj.name);
//调用函数
obj.study(); - 方式二:使用{}创建 json格式 - 格式 - var 变量名 = { //定义一个空对象
属性名1:值1, //声明属性1
属性名2:值2, //声明属性2
函数名:function(){} //声明函数
}; - 对象的访问(即:属性或函数的调用) - 变量名.属性;
变量名.函数名(); - 举例 - //对象的定义
var obj = {
name:”zhangchunsheng”,
age:18,
work:function(){
alert(“我在工作中…”);
}
};

alert(typeof(obj));
alert(obj.name);
obj.study(); #### 2.9.2 函数也是对象 - 在JavaScript中,函数也作为一种数据类型存在,而且是引用数据类型,函数名就是指向其内存空间地址的引用。 var a = function() {
return 2;
};
var b = a;
a.age = 18;
alert(b.age); //18
#### 2.9.3 this关键字的使用 - 在JavaScript函数中,this关键字指向的是调用当前函数的对象。 - 举例1: - var obj = {
name:”Tom”,
age:18,
study:function(){
alert(“好好学习,天天向上”);
},
info:function(){
alert(“name : “ + this.name + “, age = “ + this.age);
}
};

alert(obj.name);
obj.study();
obj.info(); ## 三、 JSON(最重点) ### 3.1 JSON格式的用途 在开发中凡是涉及到『跨平台数据传输』,JSON格式一定是首选。
### 3.2 JSON格式的说明 - JSON数据两端要么是{},要么是[] - {}定义JSON对象 - []定义JSON数组 - JSON对象的格式是: {key:value,key:value,…,key:value} - JOSN数组的格式是: [value,value,…,value] - key的类型固定是字符串 - value的类型可以是: - 基本数据类型 - 引用类型:JSON对象或JSON数组 正因为JSON格式中value部分还可以继续使用JSON对象或JSON数组,所以JSON格式是可以『多层嵌套』的,所以JSON格式不论多么复杂的数据类型都可以表达。
//json的格式: {key:value,key:value}
var person1 = {
“name”:”张三疯”,
“age”:189,
“address”:”武当山”
}
//其实JSON对于前端而言,就是一个对象
//console.log(person1.name) var person2 = {
“name”:”张三疯”,
“age”:189,
“address”:”武当山”,
“wife”:{
“name”:”小花”,
“age”:18,
“address”:”武当山下的小村庄”
}
}
//console.log(person2.wife.name) var person3 = {
“name”:”张三疯”,
“age”:189,
“address”:”武当山”,
“wife”:{
“name”:”小花”,
“age”:18,
“address”:”武当山下的小村庄”
},
“sons”:[
{
“name”:”奥巴马”,
“age”:1,
“address”:”武当山”
},
{
“name”:”奥拉夫”,
“age”:2,
“address”:”少林寺”
}
]
} //json数组的格式: [{key:value,key:value},{key:value,key:value}]
//var personList = [person1,person2]
### 3.3 JSON对象和JSON字符串互转 - JSON对象转JSON字符串 var jsonObj = {“stuName”:”tom”,”stuAge”:20};
var jsonStr = JSON.stringify(jsonObj); console.log(typeof jsonObj); // object
console.log(typeof jsonStr); // string - JSON字符串转JSON对象 jsonObj = JSON.parse(jsonStr);
console.log(jsonObj); // {stuName: “tom”, stuAge: 20}
## 四、 DOM DOM是Document Object Model的缩写,意思是『文档对象模型』——将HTML文档抽象成模型,再封装成对象方便用程序操作。
这是一种非常常用的编程思想:将现实世界的事物抽象成模型,这样就非常容易使用对象来量化的描述现实事物,从而把生活中的问题转化成一个程序问题,最终实现用应用软件协助解决现实问题。而在这其中『模型』就是那个连通现实世界和代码世界的桥梁。
### 4.1 DOM树的概念 浏览器把HTML文档从服务器上下载下来之后就开始按照『从上到下』的顺序『读取HTML标签』。每一个标签都会被封装成一个『对象』。
而第一个读取到的肯定是根标签html,然后是它的子标签head,再然后是head标签里的子标签……所以从html标签开始,整个文档中的所有标签都会根据它们之间的『父子关系』被放到一个『树形结构』的对象中。
这个包含了所有标签对象的整个树形结构对象就是JavaScript中的一个可以直接使用的内置对象:document。
例如,下面的标签结构:
JavaWEB葵花宝典 - 图10 会被解析为:
JavaWEB葵花宝典 - 图11 ### 4.2 各个组成部分的类型 整个文档中的一切都可以看做Node。各个具体组成部分的具体类型可以看做Node类型的子类。
其实严格来说,JavaScript并不支持真正意义上的『继承』,这里我们借用Java中的『继承』概念,从逻辑上来帮助我们理解各个类型之间的关系。 | 组成部分 | 节点类型 | 具体类型 | | —- | —- | —- | | 整个文档 | 文档节点 | Document | | HTML标签 | 元素节点 | Element | | HTML标签内的文本 | 文本节点 | Text | | HTML标签内的属性 | 属性节点 | Attr | | 注释 | 注释节点 | Comment | ### 4.3 DOM操作 由于实际开发时基本上都是使用JavaScript的各种框架来操作,而框架中的操作方式和我们现在看到的原生操作完全不同,所以下面罗列的API仅供参考,不做要求。
#### 4.3.1 在整个文档范围内查询元素节点 | 功能 | API | 返回值 | | —- | —- | —- | | 根据id值查询 | document.getElementById(“id值”) | 一个具体的元素节 | | 根据标签名查询 | document.getElementsByTagName(“标签名”) | 元素节点数组 | | 根据name属性值查询 | document.getElementsByName(“name值”) | 元素节点数组 | | 根据类名查询 | document.getElementsByClassName(“类名”) | 元素节点数组 | #### 4.3.2 在具体元素节点范围内查找子节点 | 功能 | API | 返回值 | | —- | —- | —- | | 查找子标签 | element.children | 返回子标签数组 | | 查找第一个子标签 | element.firstElementChild | 标签对象 | | 查找最后一个子标签 | element.lastElementChild | 节点对象 | #### 4.3.3 查找指定元素节点的父节点 | 功能 | API | 返回值 | | —- | —- | —- | | 查找指定元素节点的父标签 | element.parentElement | 标签对象 | #### 4.3.4 查找指定元素节点的兄弟节点 | 功能 | API | 返回值 | | —- | —- | —- | | 查找前一个兄弟标签 | node.previousElementSibling | 标签对象 | | 查找后一个兄弟标签 | node.nextElementSibling | 标签对象 | #### 4.3.5 属性操作 | 需求 | 操作方式 | | —- | —- | | 读取属性值 | 元素对象.属性名 | | 修改属性值 | 元素对象.属性名=新的属性值 | #### 4.3.6 标签体的操作 | 需求 | 操作方式 | | —- | —- | | 获取或者设置标签体的文本内容 | element.innerText | | 获取或者设置标签体的内容 | element.innerHTML | #### 4.3.7 DOM增删改操作 | API | 功能 | | —- | —- | | document.createElement(“标签名”) | 创建元素节点并返回,但不会自动添加到文档中 | | document.createTextNode(“文本值”) | 创建文本节点并返回,但不会自动添加到文档中 | | element.appendChild(ele) | 将ele添加到element所有子节点后面 | | parentEle.insertBefore(newEle,targetEle) | 将newEle插入到targetEle前面 | | parentEle.replaceChild(newEle, oldEle) | 用新节点替换原有的旧子节点 | | element.remove() | 删除某个标签 | | element.innerHTML | 读写HTML代码 | ## 五 JavaScript的事件驱动 ### 5.1 事件的概念 - HTML 事件是发生在 HTML 元素上的“事情”, 是浏览器或用户做的某些事情 - 事件通常与函数配合使用,这样就可以通过发生的事件来驱动函数执行。 ### 5.2 常见事件 | 属性 | 此事件发生在何时… | | —- | —- | | onclick | 当用户点击某个对象时调用的事件句柄。 | | ondblclick | 当用户双击某个对象时调用的事件句柄。 | | onchange | 域的内容被改变。 | | onblur | 元素失去焦点。 | | onfocus | 元素获得焦点。 | | onload | 一张页面或一幅图像完成加载。 | | onsubmit | 确认按钮被点击;表单被提交。 | | onkeydown | 某个键盘按键被按下。 | | onkeypress | 某个键盘按键被按住。 | | onkeyup | 某个键盘按键被松开。 | | onmousedown | 鼠标按钮被按下。 | | onmouseup | 鼠标按键被松开。 | | onmouseout | 鼠标从某元素移开。 | | omouseover | 鼠标移到某元素之上。 | | onmousemove | 鼠标被移动。 | ### 5.3 事件绑定的方式 #### 5.3.1 普通函数方式 说白了设置标签的属性
<标签 属性=”js代码,调用函数”></标签>
#### 5.3.2 匿名函数方式
#### 5.3.3 事件的使用介绍 - 点击事件 - 需求: 没点击一次按钮 弹出hello…
- 获得焦点(onfocus)和失去焦点(onblur) - 需求:给输入框设置获得和失去焦点 var ipt = document.getElementById(“ipt”); //绑定获取焦点事件
ipt.onfocus = function () {
console.log(“获取焦点了…”)
} //绑定失去焦点事件
ipt.onblur = function () {
console.log(“失去焦点了…”)
} - 内容改变(onchange) - 需求: 给select设置内容改变事件


  • 键盘相关的, 键盘按下(onkeydown) 键盘抬起(onkeyup)

//给输入框绑定键盘按键按下和抬起事件
ipt.onkeydown = function () {
//当按键按下的时候,数据并没有到达输入框
//输出输入框里面的内容
//console.log(ipt.value)
}

ipt.onkeyup = function () {
//输出输入框的内容:当键盘按键抬起的时候,数据已经到达了输入框
console.log(ipt.value)
}

  • 鼠标相关的, 鼠标在xx之上(onmouseover ), 鼠标按下(onmousedown),鼠标离开(onmouseout)

//给输入框绑定鼠标移入事件
ipt.onmouseover = function () {
console.log(“鼠标移入了…”)
}
//给输入框绑定鼠标移出事件
ipt.onmouseout = function () {
console.log(“鼠标移出了…”)
}

第四章 Vue

1. Vue的简介

1.1 Vue的作者介绍

在为AngularJS工作之后,Vue的作者尤雨溪开Vue.js。他声称自己的思路是提取Angular中自己喜欢的部分,构建出一款相当轻量的框架。
Vue最早发布于2014年2月。作者在Hacker News、Echo JS与 Reddit的JavaScript版块发布了最早的版本。一天之内,Vue 就登上了这三个网站的首页。
Vue是Github上最受欢迎的开源项目之一。同时,在JavaScript框架/函数库中, Vue所获得的星标数已超过React,并高于Backbone.js、Angular 2、jQuery等项目。

1.2 Vue的官网介绍

Vue (读音 /vjuː/,类似于view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。
官网地址:https://cn.vuejs.org/

2. 准备Vue.js环境

  1. Vue框架的js文件获取
  1. 创建空vue.js文件,将官网提供的vue.js文件的内容复制粘贴到本地vue.js文件中

3. Vue的入门案例

  1. 创建工程,导入vue.js文件放入工程的js文件夹中
  2. 创建demo01.html(引入vuejs,定义div,创建vue实例)

<!DOCTYPE html>








{{message}}






4. 声明式渲染

4.1 概念

4.1.1 声明式

『声明式』是相对于『编程式』而言的。

  • 声明式:告诉框架做什么,具体操作由框架完成
  • 编程式:自己编写代码完成具体操作

4.1.2 渲染

JavaWEB葵花宝典 - 图12

上图含义解释:

  • 蓝色方框:HTML标签
  • 红色圆形:动态、尚未确定的数据
  • 蓝色圆形:经过程序运算以后,计算得到的具体的,可以直接在页面上显示的数据、
  • 渲染:程序计算动态数据得到具体数据的过程

4.2 案例讲解

HTML代码

{{message}}

vue代码
// 1.创建一个JSON对象,作为new Vue时要使用的参数
var argumentJson = {

// el用于指定Vue对象要关联的HTML元素。el就是element的缩写<br />    // 通过id属性值指定HTML元素时,语法格式是:#id<br />    "el":"#app",

// data属性设置了Vue对象中保存的数据<br />    "data":{<br />        "message":"Hello Vue!"<br />    }<br />};

// 2.创建Vue对象,传入上面准备好的参数
var app = new Vue(argumentJson);
JavaWEB葵花宝典 - 图13
images

4.3 查看声明式渲染的响应式效果

JavaWEB葵花宝典 - 图14

通过验证Vue对象的『响应式』效果,我们看到Vue对象和页面上的HTML标签确实是始终保持着关联的关系,同时看到Vue在背后确实是做了大量的工作。

5. 绑定元素属性

5.1 基本语法

v-bind:HTML标签的原始属性名

5.2 案例代码

HTML代码




<!-- 同样的表达式,在标签体内通过{{}}告诉Vue这里需要渲染; --><br />    <!-- 在HTML标签的属性中,通过v-bind:属性名="表达式"的方式告诉Vue这里要渲染 --><br />    <p>{{vueValue}}</p><br /></div><br />**Vue代码**<br />// 创建Vue对象,挂载#app这个div标签<br />var app = new Vue({<br />    "el":"#app",<br />    "data":{<br />        "vueValue":"太阳当空照"<br />    }<br />});<br />**扩展:**<br />v-bind:属性名="属性值"可以简写成 :属性名="属性值"<br />

6 双向数据绑定

6.1 提出问题

JavaWEB葵花宝典 - 图15
images
而使用了双向绑定后,就可以实现:页面上数据被修改后,Vue对象中的数据属性也跟着被修改。

6.2 案例代码

HTML代码




<p>{{vueValue}}</p><br /></div><br />**Vue代码**<br />// 创建Vue对象,挂载#app这个div标签<br />var app = new Vue({<br />    "el":"#app",<br />    "data":{<br />        "vueValue":"太阳当空照"<br />    }<br />});<br />**页面效果**<br />p标签内的数据能够和文本框中的数据实现同步修改:<br />![](https://cdn.nlark.com/yuque/0/2021/png/25621085/1640875646875-3baa0140-fe83-4f0b-8453-9c052de7c5dd.png#)

扩展:

  1. v-model:value=”值” 可以简写成 v-model=”值”
  2. trim修饰符

实际开发中,要考虑到用户在输入数据时,有可能会包含前后空格。而这些前后的空格对我们程序运行来说都是干扰因素,要去掉。在v-model后面加上.trim修饰符即可实现。

Vue会帮助我们在文本框失去焦点时自动去除前后空格。

7 条件渲染

根据Vue对象中,数据属性的值来判断是否对HTML页面内容进行渲染。

7.1 v-if

HTML代码


if


JavaWEB葵花宝典 - 图16
JavaWEB葵花宝典 - 图17

Vue代码
var app = new Vue({
“el”:”#app”,
“data”:{
“flag”:true
}
});

7.2 v-if和v-else

HTML代码


if/else


JavaWEB葵花宝典 - 图18
JavaWEB葵花宝典 - 图19

Vue代码
var app02 = new Vue({
“el”:”#app02”,
“data”:{
“flag”:true
}
});

7.3 v-show

HTML代码


v-show


JavaWEB葵花宝典 - 图20

Vue代码
var app03 = new Vue({
“el”:”#app03”,
“data”:{
“flag”:true
}
});

8 列表渲染

8.1 迭代一个简单的数组

HTML代码






  • {{fruit}}



Vue代码
var app01 = new Vue({
“el”:”#app01”,
“data”:{
“fruitList”: [
“apple”,
“banana”,
“orange”,
“grape”,
“dragonfruit”
]
}
});

8.2 迭代一个对象数组

HTML代码















编号 姓名 年龄 专业
{{employee.empId}} {{employee.empName}} {{employee.empAge}} {{employee.empSubject}}


Vue代码
var app = new Vue({
“el”:”#app”,
“data”:{
“employeeList”:[
{
“empId”:11,
“empName”:”tom”,
“empAge”:111,
“empSubject”:”java”
},
{
“empId”:22,
“empName”:”jerry”,
“empAge”:222,
“empSubject”:”php”
},
{
“empId”:33,
“empName”:”bob”,
“empAge”:333,
“empSubject”:”python”
}
]
}
});

9 事件驱动

9.1 案例一: 字符串顺序反转

HTML代码


{{message}}

<!-- v-on:事件类型="事件响应函数的函数名" --><br />    <button v-on:click="reverseMessage">Click me,reverse message</button><br /></div><br />**Vue代码**<br />var app = new Vue({<br />    "el":"#app",<br />    "data":{<br />        "message":"Hello Vue!"                <br />    },<br />    "methods":{<br />        "reverseMessage":function(){<br />            this.message = this.message.split("").reverse().join("");<br />        }<br />    }<br />});<br />

9.2 案例二:获取鼠标移动时的坐标信息

HTML代码



{{position}}



Vue代码
var app = new Vue({
“el”:”#app”,
“data”:{
“position”:”暂时没有获取到鼠标的位置信息”
},
“methods”:{
“recordPosition”:function(event){
this.position = event.clientX + “ “ + event.clientY;
}
}
});
扩展:
v-on:事件名=”函数”可以简写成@事件名=”函数”

9.3 取消控件的默认行为

9.3.1 控件默认行为
  • 点超链接会跳转页面
  • 点表单提交按钮会提交表单

本来控件的默认行为是天经地义就该如此的,但是如果我们希望点击之后根据我们判断的结果再看是否要跳转,此时默认行为无脑跳转的做法就不符合我们的预期了。

9.3.2 取消方式

调用事件对象preventDefault()方法。
超链接举例
HTML代码:
超链接
JavaScript代码:
document.getElementById(“anchor”).onclick = function() {
console.log(“我点击了一个超链接”);
//event.preventDefault();
}
表单提交按钮举例
HTML代码:




JavaScript代码:
document.getElementById(“submitBtn”).onclick = function() {
console.log(“我点击了一个表单提交按钮”);
event.preventDefault();
}

9.4 阻止事件冒泡

JavaWEB葵花宝典 - 图21
images
图中的两个div,他们的HTML标签是:




点击里面的div同时也等于点击了外层的div,此时如果两个div上都绑定了单击响应函数那么就都会被触发:
document.getElementById(“outterDiv”).onclick = function() {
console.log(“外层div的事件触发了”);
}

document.getElementById(“innerDiv”).onclick = function() {
console.log(“内层div的事件触发了”);
}
所以事件冒泡就是一个事件会不断向父元素传递,直到window对象。
如果这不是我们想要的效果那么可以使用事件对象的stopPropagation()函数阻止。
document.getElementById(“innerDiv”).onclick = function() {
console.log(“内层div的事件触发了”);

event.stopPropagation();<br />}<br />

9.5 Vue事件修饰符

对于事件修饰符,Vue官网的描述是:
在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。

9.5.1 取消控件的默认行为

控件的默认行为指的是:

  • 点击超链接跳转页面
  • 点击表单提交按钮提交表单

实现这个需求使用的Vue事件修饰符是:.prevent
超链接




9.5.2 取消事件冒泡

实现这个需求使用的Vue事件修饰符是:.stop




10 侦听属性

10.1 提出需求

尊姓:{{firstName}}


大名:{{lastName}}


尊姓:

大名:

全名:{{fullName}}



在上面代码的基础上,我们希望firstName或lastName属性发生变化时,修改fullName属性。此时需要对firstName或lastName属性进行『侦听』。
具体来说,所谓『侦听』就是对message属性进行监控,当firstName或lastName属性的值发生变化时,调用我们准备好的函数。
##### 10.2 Vue代码 在watch属性中声明对firstName和lastName属性进行『侦听』的函数:
var app = new Vue({
“el”:”#app”,
“data”:{
“firstName”:”jim”,
“lastName”:”green”,
“fullName”:”jim green”
},
“watch”:{
“firstName”:function(inputValue){
this.fullName = inputValue + “ “ + this.lastName;
},
“lastName”:function(inputValue){
this.fullName = this.firstName + “ “ + inputValue;
}
}
});
#### 11 Vue的生命周期 ##### 11.1 概念 在我们各种语言的编程领域中,『生命周期』都是一个非常常见的概念。一个对象从创建、初始化、工作再到释放、清理和销毁,会经历很多环节的演变。比如我们在JavaSE阶段学习过线程的生命周期,今天学习Vue对象的生命周期,将来还要学习Servlet、Filter等Web组件的生命周期。
##### 11.2 Vue对象的生命周期 JavaWEB葵花宝典 - 图22
images
##### 2.13.3 生命周期钩子函数 Vue允许我们在特定的生命周期环节中通过钩子函数来加入我们的代码。

{{message}}




new Vue({
“el”:”#app”,
“data”:{
“message”:”hello”
},
“methods”:{
“changeValue”:function(){
this.message = “new hello”;
}
}, // 1.实例创建之前
“beforeCreate”:function(){
console.log(“beforeCreate:”+this.message);
}, // 2.实例创建完成
“created”:function(){
console.log(“created:”+this.message);
}, // 3.数据挂载前
“beforeMount”:function(){
console.log(“beforeMount:”+document.getElementById(“content”).innerText);
}, // 4.数据已经挂载
“mounted”:function(){
console.log(“mounted:”+document.getElementById(“content”).innerText);
}, // 5.数据更新前
“beforeUpdate”:function(){
console.log(“beforeUpdate:”+document.getElementById(“content”).innerText);
}, // 6.数据更新之后
“updated”:function(){
console.log(“updated:”+document.getElementById(“content”).innerText);
}
});
## 第五章 XML ### 1. 内容讲解 #### 1.1 配置文件 ##### 1.1.1 配置文件的作用 配置文件是用于给应用程序提供配置参数以及初始化设置的一些有特殊格式的文件
##### 1.1.1 常见的配置文件类型 1. properties文件,例如druid连接池就是使用properties文件作为配置文件 1. XML文件,例如Tomcat就是使用XML文件作为配置文件 1. YAML文件,例如SpringBoot就是使用YAML作为配置文件 1. json文件,通常用来做文件传输,也可以用来做前端或者移动端的配置文件 #### 1.2 properties文件 ##### 1.2.1 文件示例 atguigu.jdbc.url=jdbc:mysql://192.168.198.100:3306/mybatis1026
atguigu.jdbc.driver=com.mysql.jdbc.Driver
atguigu.jdbc.username=root
atguigu.jdbc.password=atguigu
##### 1.2.2 语法规范 - 由键值对组成 - 键和值之间的符号是等号 - 每一行都必须顶格写,前面不能有空格之类的其他符号 #### 1.3 XML文件 ##### 1.3.1 文件示例 <?xml version=”1.0” encoding=”UTF-8”?>
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance
xsi:schemaLocation=”http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd”
version=”4.0”>

dispatcherServlet
org.springframework.web.servlet.DispatcherServlet

contextConfigLocation
classpath:spring-mvc.xml

1


dispatcherServlet

/


##### 1.3.2 概念介绍 XML是eXtensible Markup Language的缩写,翻译过来就是可扩展标记语言。所以很明显,XML和HTML一样都是标记语言,也就是说它们的基本语法都是标签。
可扩展
可扩展三个字表面上的意思是XML允许自定义格式。但是别美,这不代表你可以随便写。
JavaWEB葵花宝典 - 图23 在XML基本语法规范的基础上,你使用的那些第三方应用程序、框架会通过设计『XML约束』的方式『强制规定』配置文件中可以写什么和怎么写,规定之外的都不可以写。
XML基本语法这个知识点的定位是:我们不需要从零开始,从头到尾的一行一行编写XML文档,而是在第三方应用程序、框架已提供的配置文件的基础上修改。要改成什么样取决于你的需求,而怎么改取决于XML基本语法和具体的XML约束。
##### 1.3.3 XML的基本语法 - XML文档声明 这部分基本上就是固定格式,要注意的是文档声明一定要从第一行第一列开始写
<?xml version=”1.0” encoding=”UTF-8”?> - 根标签 根标签有且只能有一个。 - 标签关闭 - 双标签:开始标签和结束标签必须成对出现。 - 单标签:单标签在标签内关闭。 - 标签嵌套 - 可以嵌套,但是不能交叉嵌套。 - 注释不能嵌套 - 标签名、属性名建议使用小写字母 - 属性 - 属性必须有值 - 属性值必须加引号,单双都行 看到这里大家一定会发现XML的基本语法和HTML的基本语法简直如出一辙。其实这不是偶然的,XML基本语法+HTML约束=HTML语法。在逻辑上HTML确实是XML的子集。
<!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.01 Transitional//EN”
http://www.w3.org/TR/html4/loose.dtd">
从HTML4.01版本的文档类型声明中可以看出,这里使用的DTD类型的XML约束。也就是说http://www.w3.org/TR/html4/loose.dtd这个文件定义了HTML文档中可以写哪些标签,标签内可以写哪些属性,某个标签可以有什么样的子标签。
##### 1.3.4 XML的约束(稍微了解) 将来我们主要就是根据XML约束中的规定来编写XML配置文件,而且会在我们编写XML的时候根据约束来提示我们编写, 而XML约束主要包括DTD和Schema两种。 - DTD - Schema Schema约束要求我们一个XML文档中,所有标签,所有属性都必须在约束中有明确的定义。
下面我们以web.xml的约束声明为例来做个说明:
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance
xsi:schemaLocation=”http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd”
version=”4.0”> | 属性名 | 作用 | | —- | —- | | xmlns | 指出当前XML文档约束规则的名称空间在哪里
我们就是通过这个属性来引用一个具体的名称空间 | | xmlns:xsi | 指出xmlns这个属性是在哪个约束文档中被定义的 | | xsi:schemaLocation | 语法格式:在xsi名称空间下引用schemaLocation属性
配置含义:指定当前XML文档中所用到的约束文档本身的文件的地址 | ##### 1.3.5 XML解析(重点) ###### 1.3.5.1 XML解析的作用 用Java代码读取xml中的数据
###### 1.3.5.2 XML的两种解析方式 1. DOM解析:将文档加载进内存,形成一颗dom树(document对象),将文档的各个组成部分封装为一些对象。 - 优点:因为在内存中会形成dom树,程序员可以以面向对象的方式操作XML文件,写代码就非常方便,可以对dom树进行增删改查。 - 缺点:dom树非常占内存,解析速度慢。所以一般解析体积较大的XML文件的时候不会采用DOM解析 2. SAX解析:逐行读取,基于事件驱动,解析一行释放一行,内存占用非常小 建议:一般会采用DOM解析方式来解析XML,除非是解析体积很大的XML文件才会采用SAX解析
###### 1.3.5.3 常见的XML解析器 在使用Java代码解析XML的时候,我们通常不会直接使用JDK内置的原生的DOM或者SAX解析XML,因为代码实在是太复杂了。一些公司和组织已经封装好了优秀的XML解析器,我们通常会使用第三方XML解析器来解析XML 1. JAXP: sun公司提供的解析。支持dom和sax。(不常用) 1. JDOM 1. DOM4J(常用) ###### 1.3.5.4 DOM4J的使用步骤 1. 导入jar包 dom4j.jar 1. 创建解析器对象(SAXReader) 1. 解析xml 获得Document对象 1. 获取根节点RootElement 1. 获取根节点下的子节点 ###### 1.3.5.5 DOM4J的API介绍 1. 创建SAXReader对象 SAXReader saxReader = new SAXReader(); 1. 解析XML获取Document对象: 需要传入要解析的XML文件的字节输入流 Document document = reader.read(inputStream); 1. 获取文档的根标签 Element rootElement = documen.getRootElement() 1. 获取标签的子标签 //获取所有子标签
List sonElementList = rootElement.elements();
//获取指定标签名的子标签
List sonElementList = rootElement.elements(“标签名”); 1. 获取标签体内的文本 String text = element.getText(); 1. 获取标签的某个属性的值 String value = element.AttributeValue(“属性名”);
###### 1.3.5.6 XPATH的使用介绍 1. XPATH的作用: 使用规则匹配直接查找xml文件中的指定节点 1. XPATH的使用步骤: 1. 引入dom4j和xpath的jar包 1. 创建解析器对象 1. 解析xml 获得document对象 1. 使用document对象调用方法,根据路径规则查找节点 3. XPATH的API: - selectSingleNode(“路径规则”): 根据路径规则,查找满足条件的第一个节点 - selectNodes(“路径规则”): 根据路径规则,查找满足条件的所有节点 4. XPATH的路径规则的编写: 见附件资料 ## 第六章 Tomcat(最重要) ### 1. Web服务器 - Web服务器通常由硬件和软件共同构成。 - 硬件:电脑,提供服务供其它客户电脑访问 - JavaWEB葵花宝典 - 图24 -
- 软件:电脑上安装的服务器软件,安装后能提供服务给网络中的其他计算机,将本地文件映射成一个虚拟的url地址供网络中的其他人访问。 - Web服务器主要用来接收客户端发送的请求和响应客户端请求。 - 常见的JavaWeb服务器: - Tomcat(Apache):当前应用最广的JavaWeb服务器 - JBoss(Redhat红帽):支持JavaEE,应用比较广EJB容器 –> SSH轻量级的框架代替 - GlassFish(Orcale):Oracle开发JavaWeb服务器,应用不是很广 - Resin(Caucho):支持JavaEE,应用越来越广 - Weblogic(Orcale):要钱的!支持JavaEE,适合大型项目 - Websphere(IBM):要钱的!支持JavaEE,适合大型项目 ### 2 Tomcat服务器 #### 2.1 Tomcat简介 Tomcat是Apache 软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,由Apache、Sun 和其他一些公司及个人共同开发而成。由于有了Sun 的参与和支持,最新的Servlet 和JSP 规范总是能在Tomcat 中得到体现,因为Tomcat 技术先进、性能稳定,而且免费,因而深受Java 爱好者的喜爱并得到了部分软件开发商的认可,成为目前比较流行的Web 应用服务器。
#### 2.2 Tomcat下载 - Tomcat官方网站:http://tomcat.apache.org/ - 安装版:需要安装,一般不考虑使用。 - 解压版: 直接解压缩使用,我们使用的版本。 - 因为tomcat服务器软件需要使用java环境,所以需要正确配置JAVA_HOME #### 2.3 Tomcat的版本 - 版本:企业用的比较广泛的是7.0和8.0的。授课我们使用8.0。 - tomcat6以下都不用了,所以我们从tomcat6开始比较: - tomcat6 支持servlet2.5、jsp2.1、el - tomcat7 支持servlet3.0、jsp2.2、el2.2、websocket1.1 - tomcat8 支持servlet3.1、jsp2.3、el3.0、websocket1.1 - tomcat9 支持servlet4.0、jsp2.3、el3.0、websocket1.1 #### 2.4 安装 解压apache-tomcat-8.5.27-windows-x64.zip到非中文无空格目录中
JavaWEB葵花宝典 - 图25 #### 2.5 配置 启动Tomcat前,需要配置JAVA_HOME的环境变量
#### 2.6 启动 在命令行中运行catalina run或者 Tomcat解压目录下双击startup.bat 启动Tomcat服务器,在浏览器地址栏访问如下地址进行测试
http://localhost:8080
JavaWEB葵花宝典 - 图26 如果启动失败,查看如下的情况:
情况一:如果双击startup.bat后窗口一闪而过,请查看JAVA_HOME是否配置正确。
startup.bat会调用catalina.bat,而catalina.bat会调用setclasspath.bat,setclasspath.bat会使用JAVA_HOME环境变量,所以我们必须在启动Tomcat之前把JAVA_HOME配置正确。
情况二:如果启动失败,提示端口号被占用,则将默认的8080端口修改为其他未使用的值,例如8989等。
【方法】 打开:解压目录\conf\server.xml,找到第一个Connector标签,修改port属性
web服务器在启动时,实际上是监听了本机上的一个端口,当有客户端向该端口发送请求时,web服务器就会处理请求。但是如果不是向其所监听的端口发送请求,web服务器不会做任何响应。例如:Tomcat启动监听了8989端口,而访问的地址是http://localhost:8080,将不能正常访问。
#### 2.7 在IDEA中创建Tomcat 在IDEA中配置好Tomcat后,可以直接通过IDEA控制Tomcat的启动和停止,而不用再去操作startup.bat和shutdown.bat。
① 点击File—>Settings 或者直接点击图标
JavaWEB葵花宝典 - 图27 接着:
JavaWEB葵花宝典 - 图28 接着:
JavaWEB葵花宝典 - 图29 ### 3 动态Web工程部署与测试 #### 3.1 创建动态Web工程 JavaWEB葵花宝典 - 图30 接着:
JavaWEB葵花宝典 - 图31 JavaWEB葵花宝典 - 图32 #### 3.2 开发项目目录结构说明 - src:存放Java源代码的目录。 - web:存放的是需要部署到服务器的文件 - WEB-INF:这个目录下的文件,是不能被客户端直接访问的。 - lib:用于存放该工程用到的库。粘贴过来以后 - web.xml:web工程的配置文件,完成用户请求的逻辑名称到真正的servlet类的映射。 - 凡是客户端能访问的资源(.html或 .jpg)必须跟WEB-INF在同一目录,即放在Web根目录下的资源,从客户端是可以通过URL地址直接访问的。 JavaWEB葵花宝典 - 图33 #### 3.3 tomcat实例的基础设置 由于每次创建项目随之创建的tomcat实例名字都类似,所以建议修改一下tomcat实例的名称
JavaWEB葵花宝典 - 图34 在如下界面进行基础设置
JavaWEB葵花宝典 - 图35 JavaWEB葵花宝典 - 图362.11 导入现有的Module
如果你想把老师发给你的module导入自己的project中运行起来,可以参考下面的操作:
做下面操作前,需要把要导入的module复制到project目录下。
JavaWEB葵花宝典 - 图37 JavaWEB葵花宝典 - 图38 JavaWEB葵花宝典 - 图39 JavaWEB葵花宝典 - 图40 JavaWEB葵花宝典 - 图41 JavaWEB葵花宝典 - 图42 JavaWEB葵花宝典 - 图43 JavaWEB葵花宝典 - 图44 JavaWEB葵花宝典 - 图45 JavaWEB葵花宝典 - 图46 # 第七章 HTTP协议 ## 一、 HTTP协议简介 JavaWEB葵花宝典 - 图47 - HTTP 超文本传输协议 (HTTP-Hypertext transfer protocol),是一个属于应用层的面向对象的协议,由于其简捷、快速的方式,适用于分布式超媒体信息系统。它于1990年提出,经过十几年的使用与发展,得到不断地完善和扩展。它是一种详细规定了浏览器和万维网服务器之间互相通信的规则,通过因特网传送万维网文档的数据传送协议。 - 客户端与服务端通信时传输的内容我们称之为报文HTTP协议就是规定报文的格式。 - HTTP就是一个通信规则,这个规则规定了客户端发送给服务器的报文格式,也规定了服务器发送给客户端的报文格式。实际我们要学习的就是这两种报文。客户端发送给服务器的称为”请求报文“,服务器发送给客户端的称为”响应报文“。 - 类比于生活中案例:① 毕业租房,签署租房协议,规范多方需遵守的规则。②与远方的朋友的写信。信封的规范。 - 实际互联网: - 客户端 与 服务端进行通信。比如:用户 —-> 访问京东(就是一个数据传输的过程),数据传输需要按照一种协议去传输。就如,用户给服务器写信;服务器给用户回信。有格式:协议。HTTP协议规定通信规则。规定互联网之间如何传输数据。 - 信:报文。 - 写信:用户给服务器写信,用户给服务器发请求。把发的请求所有数据,请求报文 - 回信:服务器回信给用户,回给浏览器。把服务器响应浏览器的所有数据,响应报文 ## 二、 HTTP协议的发展历程 - 超文本传输协议的前身是世外桃源(Xanadu)项目,超文本的概念是泰德·纳尔森(Ted Nelson)在1960年代提出的。进入哈佛大学后,纳尔森一直致力于超文本协议和该项目的研究,但他从未公开发表过资料。1989年,蒂姆·伯纳斯·李(Tim Berners Lee)在CERN(欧洲原子核研究委员会 = European Organization for Nuclear Research)担任软件咨询师的时候,开发了一套程序,奠定了万维网(WWW = World Wide Web)的基础。1990年12月,超文本在CERN首次上线。1991年夏天,继Telnet等协议之后,超文本转移协议成为互联网诸多协议的一分子。 - 当时,Telnet协议解决了一台计算机和另外一台计算机之间一对一的控制型通信的要求。邮件协议解决了一个发件人向少量人员发送信息的通信要求。文件传输协议解决一台计算机从另外一台计算机批量获取文件的通信要求,但是它不具备一边获取文件一边显示文件或对文件进行某种处理的功能。新闻传输协议解决了一对多新闻广播的通信要求。而超文本要解决的通信要求是:在一台计算机上获取并显示存放在多台计算机里的文本、数据、图片和其他类型的文件;它包含两大部分:超文本转移协议和超文本标记语言(HTML)。HTTP、HTML以及浏览器的诞生给互联网的普及带来了飞跃。 ## 三、 HTTP协议的会话方式 - 浏览器与服务器之间的通信过程要经历四个步骤 JavaWEB葵花宝典 - 图48 - 浏览器与WEB服务器的连接过程是短暂的,每次连接只处理一个请求和响应。对每一个页面的访问,浏览器与WEB服务器都要建立一次单独的连接。 - 浏览器到WEB服务器之间的所有通讯都是完全独立分开的请求和响应对。 ## 四、 HTTP1.0和HTTP1.1的区别 在HTTP1.0版本中,浏览器请求一个带有图片的网页,会由于下载图片而与服务器之间开启一个新的连接;但在HTTP1.1版本中,允许浏览器在拿到当前请求对应的全部资源后再断开连接,提高了效率。
JavaWEB葵花宝典 - 图49 ## 五、 不同浏览器监听HTTP操作 ### 5.1 Chrome中F12可查看 JavaWEB葵花宝典 - 图50 ### 5.4 FireFox中F12可查看 JavaWEB葵花宝典 - 图51 ## 六、 报文 ### 6.1 报文格式 JavaWEB葵花宝典 - 图52 - 报文: - 请求报文:浏览器发给服务器 - 响应报文:服务器发回给浏览器 ### 6.2 请求报文 #### 6.2.1 报文格式 (4部分) - 请求首行(请求行); - 请求头信息(请求头); - 空行; - 请求体; #### 6.2.2 GET请求 1、由于请求参数在请求首行中已经携带了,所以没有请求体,也没有请求空行 2、请求参数拼接在url地址中,地址栏可见[url?name1=value1&name2=value2],不安全 3、由于参数在地址栏中携带,所以由大小限制[地址栏数据大小一般限制为4k],只能携带纯文本 4、get请求参数只能上传文本数据 5、没有请求体。所以封装和解析都快,效率高, 浏览器默认提交的请求都是get请求[比如:① 地址栏输入url地址回车,②点击超链接a , ③ form表单默认方式…] - 请求首行 GET /05_web_tomcat/login_success.html?username=admin&password=123213 HTTP/1.1 请求方式 访问的服务器中的资源路径?get请求参数 协议版本 - 请求头 Host: localhost:8080 主机虚拟地址
Connection: keep-alive 长连接
Upgrade-Insecure-Requests: 1 请求协议的自动升级[http的请求,服务器却是https的,浏览器自动会将请求协议升级为https的]
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36
- 用户系统信息
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8
- 浏览器支持的文件类型
Referer: http://localhost:8080/05_web_tomcat/login.html
- 当前页面的上一个页面的路径[当前页面通过哪个页面跳转过来的]: 可以通过此路径跳转回上一个页面, 广告计费,防止盗链
Accept-Encoding: gzip, deflate, br
- 浏览器支持的压缩格式
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
- 浏览器支持的语言 #### 6.2.3 POST请求 - POST请求要求将form标签的method的属性设置为post JavaWEB葵花宝典 - 图53 1、POST请求有请求体,而GET请求没有请求体。 2、post请求数据在请求体中携带,请求体数据大小没有限制,可以用来上传所有内容[文件、文本] 3、只能使用post请求上传文件 4、post请求报文多了和请求体相关的配置[请求头] 5、地址栏参数不可见,相对安全 6、post效率比get低 - 请求首行 POST /05_web_tomcat/login_success.html HTTP/1.1 - 请求头 Host: localhost:8080
Connection: keep-alive
Content-Length: 31 -请求体内容的长度
Cache-Control: max-age=0 -无缓存
Origin: http://localhost:8080
Upgrade-Insecure-Requests: 1 -协议的自动升级
Content-Type: application/x-www-form-urlencoded -请求体内容类型[服务器根据类型解析请求体参数]
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8
Referer: http://localhost:8080/05_web_tomcat/login.html
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
Cookie:JSESSIONID- - 请求空行 - 请求体:浏览器提交给服务器的内容 username=admin&password=1232131 ### 6.3 响应报文 #### 6.3.1 报文格式(4部分) - 响应首行(响应行); - 响应头信息(响应头); - 空行; - 响应体; #### 6.3.2 具体情况 - 响应首行: - HTTP/1.1 200 OK 说明:响应协议为HTTP1.1,响应状态码为200,表示请求成功; - 响应头: - Server: Apache-Coyote/1.1 服务器的版本信息
Accept-Ranges: bytes
ETag: W/“157-1534126125811”
Last-Modified: Mon, 13 Aug 2018 02:08:45 GMT
Content-Type: text/html 响应体数据的类型[浏览器根据类型解析响应体数据]
Content-Length: 157 响应体内容的字节数
Date: Mon, 13 Aug 2018 02:47:57 GMT 响应的时间,这可能会有8小时的时区差 - 响应空行 - 响应体 - <!DOCTYPE html>






恭喜你,登录成功了…

#### 6.3.3 响应码 响应码对浏览器来说很重要,它告诉浏览器响应的结果。比较有代表性的响应码如下: - 200:请求成功,浏览器会把响应体内容(通常是html)显示在浏览器中; - 404:请求的资源没有找到,说明客户端错误的请求了不存在的资源; - JavaWEB葵花宝典 - 图54 -
- 500:请求资源找到了,但服务器内部出现了错误; - JavaWEB葵花宝典 - 图55 -
- 302:重定向,当响应码为302时,表示服务器要求浏览器重新再发一个请求,服务器会发送一个响应头Location,它指定了新请求的URL地址; 除此之外,其它一些响应码如下:
200 - 服务器成功返回网页
404 - 请求的网页不存在
503 - 服务不可用
详细分解: 1xx(临时响应)
表示临时响应并需要请求者继续执行操作的状态代码。 代码 说明
100 (继续) 请求者应当继续提出请求。服务器返回此代码表示已收到请求的第一部分,正在等待其余部分。
101 (切换协议) 请求者已要求服务器切换协议,服务器已确认并准备切换。 2xx (成功)
表示成功处理了请求的状态代码。 代码 说明
200 (成功) 服务器已成功处理了请求。通常,这表示服务器提供了请求的网页。
201 (已创建) 请求成功并且服务器创建了新的资源。
202 (已接受) 服务器已接受请求,但尚未处理。
203 (非授权信息) 服务器已成功处理了请求,但返回的信息可能来自另一来源。
204 (无内容) 服务器成功处理了请求,但没有返回任何内容。
205 (重置内容) 服务器成功处理了请求,但没有返回任何内容。
206 (部分内容) 服务器成功处理了部分 GET 请求。 3xx (重定向)
表示要完成请求,需要进一步操作。 通常,这些状态代码用来重定向。 代码 说明
300 (多种选择) 针对请求,服务器可执行多种操作。服务器可根据请求者 (user agent) 选择一项操作,或提供操作列表供请求者选择。
301 (永久移动) 请求的网页已永久移动到新位置。服务器返回此响应(对 GET 或 HEAD 请求的响应)时,会自动将请求者转到新位置。
302 (临时移动) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。
303 (查看其他位置) 请求者应当对不同的位置使用单独的 GET 请求来检索响应时,服务器返回此代码。
304 (未修改) 自从上次请求后,请求的网页未修改过。服务器返回此响应时,不会返回网页内容。
305 (使用代理) 请求者只能使用代理访问请求的网页。如果服务器返回此响应,还表示请求者应使用代理。
307 (临时重定向) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。 4xx(请求错误)
这些状态代码表示请求可能出错,妨碍了服务器的处理。 代码 说明
400 (错误请求) 服务器不理解请求的语法。
401 (未授权) 请求要求身份验证。 对于需要登录的网页,服务器可能返回此响应。
403 (禁止) 服务器拒绝请求。
404 (未找到) 服务器找不到请求的网页。
405 (方法禁用) 禁用请求中指定的方法。
406 (不接受) 无法使用请求的内容特性响应请求的网页。
407 (需要代理授权) 此状态代码与 401(未授权)类似,但指定请求者应当授权使用代理。
408 (请求超时) 服务器等候请求时发生超时。
409 (冲突) 服务器在完成请求时发生冲突。服务器必须在响应中包含有关冲突的信息。
410 (已删除) 如果请求的资源已永久删除,服务器就会返回此响应。
411 (需要有效长度) 服务器不接受不含有效内容长度标头字段的请求。
412 (未满足前提条件) 服务器未满足请求者在请求中设置的其中一个前提条件。
413 (请求实体过大) 服务器无法处理请求,因为请求实体过大,超出服务器的处理能力。
414 (请求的 URI 过长) 请求的 URI(通常为网址)过长,服务器无法处理。
415 (不支持的媒体类型) 请求的格式不受请求页面的支持。
416 (请求范围不符合要求) 如果页面无法提供请求的范围,则服务器会返回此状态代码。
417 (未满足期望值) 服务器未满足”期望”请求标头字段的要求。 5xx(服务器错误)
这些状态代码表示服务器在尝试处理请求时发生内部错误。 这些错误可能是服务器本身的错误,而不是请求出错。 代码 说明
500 (服务器内部错误) 服务器遇到错误,无法完成请求。
501 (尚未实施) 服务器不具备完成请求的功能。例如,服务器无法识别请求方法时可能会返回此代码。
502 (错误网关) 服务器作为网关或代理,从上游服务器收到无效响应。
503 (服务不可用) 服务器目前无法使用(由于超载或停机维护)。通常,这只是暂时状态。
504 (网关超时) 服务器作为网关或代理,但是没有及时从上游服务器收到请求。
505 (HTTP 版本不受支持) 服务器不支持请求中所用的 HTTP 协议版本。 HttpWatch状态码Result is 200 - 服务器成功返回网页,客户端请求已成功。
302 - 对象临时移动。服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。
304 - 属于重定向。自上次请求后,请求的网页未修改过。服务器返回此响应时,不会返回网页内容。
401 - 未授权。请求要求身份验证。 对于需要登录的网页,服务器可能返回此响应。
404 - 未找到。服务器找不到请求的网页。
2xx - 成功。表示服务器成功地接受了客户端请求。
3xx - 重定向。表示要完成请求,需要进一步操作。客户端浏览器必须采取更多操作来实现请求。例如,浏览器可能不得不请求服务器上的不同的页面,或通过代理服务器重复该请求。
4xx - 请求错误。这些状态代码表示请求可能出错,妨碍了服务器的处理。
5xx - 服务器错误。表示服务器在尝试处理请求时发生内部错误。 这些错误可能是服务器本身的错误,而不是请求出错。 # 第八章 Servlet组件 ## 一、 我们为什么需要Servlet? ### 1.1 Web应用基本运行模式 - 生活中的例子 JavaWEB葵花宝典 - 图56 - Web应用运行模 JavaWEB葵花宝典 - 图57 ### 1.2 Web服务器中Servlet作用举例 - 举例一:插入数据 JavaWEB葵花宝典 - 图58 - 举例二:查询数据 通过网页驱动服务器端的Java程序。在网页上显示Java程序返回的数据。
JavaWEB葵花宝典 - 图59 ## 二、 什么是Servlet? 如果把Web应用比作一个餐厅,Servlet就是餐厅中的服务员——负责接待顾客、上菜、结账。
JavaWEB葵花宝典 - 图60 - 从广义上来讲,Servlet规范是Sun公司制定的一套技术标准,包含与Web应用相关的一系列接口,是Web应用实现方式的宏观解决方案。而具体的Servlet容器负责提供标准的实现。 - 从狭义上来讲,Servlet指的是javax.servlet.Servlet接口及其子接口,也可以指实现了Servlet接口的实现类。 - Servlet(Server Applet)作为服务器端的一个组件,它的本意是“服务器端的小程序”。 - Servlet的实例对象由Servlet容器负责创建; tomcat—>web容器 (包括servlet容器和其他容器) - Servlet的方法由容器在特定情况下调用; - Servlet容器会在Web应用卸载时销毁Servlet对象的实例。 ## 三、 如何使用Servlet? ### 3.1 操作步骤 - 复习:使用一个接口的传统方式: - 创建一个类实现接口 - new 实现类的对象 - 调用类的方法等 -
- 使用Servlet接口的方式: - ① 搭建Web开发环境 - ② 创建动态Web工程 - ③ 创建javax.servlet.Servlet接口的实现类:com.atguigu.servlet.MyFirstServlet - ④ 在service(ServletRequest, ServletResponse)方法中编写如下代码,输出响应信息: @Override
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
//1.编写输出语句,证明当前方法被调用
System.out.println(“Servlet worked…”);
//2.通过PrintWriter对象向浏览器端发送响应信息
PrintWriter writer = res.getWriter();
writer.write(“Servlet response”);
writer.close();
}
⑤ 在web.xml配置文件中注册MyFirstServlet



MyFirstServlet

com.atguigu.servlet.MyFirstServlet



MyFirstServlet

/MyFirstServlet

说明: - :这个url-pattern可以配置多个,这时表示的就是访问这些url都会触发这个Servlet进行响应,运行浏览器,访问刚才配置的url路径,Servlet的service方法就会被调用。 - 中的文本内容必须以 / 或 . 开始书写路径。相当于将资源映射到项目根目录下形成虚拟的资源文件。 - 中的可以声明多个,可以通过任意一个都可以访问。但是开发中一般只会配置一个。 ⑥ 在WebContent目录下创建index.html
⑦ 在index.html中加入超链接 To Servlet
⑧ 点击超链接测试Servlet
### 3.2 运行分析(执行原理) - index.html JavaWEB葵花宝典 - 图61 - web.xml JavaWEB葵花宝典 - 图62 - 如果配置文件一旦修改,需要重启服务器来重新部署web项目。 ### 3.3 Servlet作用总结 - 接收请求 【解析请求报文中的数据:请求参数】 - 处理请求 【DAO和数据库交互】 - 完成响应 【设置响应报文】 JavaWEB葵花宝典 - 图63 ## 四、 Servlet生命周期(重要) ### 4.1 Servlet生命周期概述 - 应用程序中的对象不仅在空间上有层次结构的关系,在时间上也会因为处于程序运行过程中的不同阶段而表现出不同状态和不同行为——这就是对象的生命周期。 - 简单的叙述生命周期,就是对象在容器中从开始创建到销毁的过程。 ### 4.2 Servlet容器 Servlet对象是Servlet容器创建的,生命周期方法都是由容器调用的。这一点和我们之前所编写的代码有很大不同。在今后的学习中我们会看到,越来越多的对象交给容器或框架来创建,越来越多的方法由容器或框架来调用,开发人员要尽可能多的将精力放在业务逻辑的实现上。
### 4.3 Servlet生命周期的主要过程 #### ① Servlet对象的创建:构造器 - 默认情况下,Servlet容器第一次收到HTTP请求时创建对应Servlet对象。 - 容器之所以能做到这一点是由于我们在注册Servlet时提供了全类名,容器使用反射技术创建了Servlet的对象。 #### ② Servlet对象初始化:init() - Servlet容器创建Servlet对象之后,会调用init(ServletConfig config)方法。 - 作用:是在Servlet对象创建后,执行一些初始化操作。例如,读取一些资源文件、配置文件,或建立某种连接(比如:数据库连接) - init()方法只在创建对象时执行一次,以后再接到请求时,就不执行了 - 在javax.servlet.Servlet接口中,public void init(ServletConfig config)方法要求容器将ServletConfig的实例对象传入,这也是我们获取ServletConfig的实例对象的根本方法。 #### ③ 处理请求:service() - 在javax.servlet.Servlet接口中,定义了service(ServletRequest req, ServletResponse res)方法处理HTTP请求。 - 在每次接到请求后都会执行。 - 上一节提到的Servlet的作用,主要在此方法中体现。 - 同时要求容器将ServletRequest对象和ServletResponse对象传入。 #### ④ Servlet对象销毁:destroy() - 服务器重启、服务器停止执行或Web应用卸载时会销毁Servlet对象,会调用public void destroy()方法。 - 此方法用于销毁之前执行一些诸如释放缓存、关闭连接、保存内存数据持久化等操作。 ### 4.4 Servlet请求过程 - 第一次请求 - 调用构造器,创建对象 - 执行init()方法 - 执行service()方法 - 后面请求 - 执行service()方法 - 对象销毁前 - 执行destroy()方法 ## 五、 Servlet的两个重要接口 ### 5.1 ServletConfig接口 JavaWEB葵花宝典 - 图64 - ServletConfig接口封装了Servlet配置信息,这一点从接口的名称上就能够看出来。 - 每一个Servlet都有一个唯一对应的ServletConfig对象,代表当前Servlet的配置信息。 - 对象由Servlet容器创建,并传入生命周期方法init(ServletConfig config)中。可以直接获取使用。 - 代表当前Web应用的ServletContext对象也封装到了ServletConfig对象中,使ServletConfig对象成为了获取ServletContext对象的一座桥梁。 - ServletConfig对象的主要功能 - 获取Servlet名称:getServletName() - 获取全局上下文ServletContext对象:getServletContext() - 获取Servlet初始化参数:getInitParameter(String) / getInitParameterNames()。 - 使用如下: - JavaWEB葵花宝典 - 图65 -
- 通过String info = config.getInitParameter(“url”);的方式获取value值 -
### 5.2 ServletContext接口 JavaWEB葵花宝典 - 图66 - Web容器在启动时,它会为每个Web应用程序都创建一个唯一对应的ServletContext对象,意思是Servlet上下文,代表当前Web应用。 - 由于一个Web应用程序中的所有Servlet都共享同一个ServletContext对象,所以ServletContext对象也被称为 application 对象(Web应用程序对象)。 - 对象由Servlet容器在项目启动时创建,通过ServletConfig对象的getServletContext()方法获取。在项目卸载时销毁。 - ServletContext对象的主要功能 - ① 获取项目的上下文路径(带/的项目名): getContextPath() - @Override
public void init(ServletConfig config) throws ServletException {
ServletContext application = config.getServletContext();
System.out.println(“全局上下文对象:”+application);
String path = application.getContextPath();
System.out.println(“全局上下文路径:”+path);// /06_Web_Servlet
} - ② 获取虚拟路径所映射的本地真实路径:getRealPath(String path) - 虚拟路径:浏览器访问Web应用中资源时所使用的路径。 - 本地路径:资源在文件系统中的实际保存路径。 - 作用:将用户上传的文件通过流写入到服务器硬盘中。 - @Override
public void init(ServletConfig config) throws ServletException {
//1.获取ServletContext对象
ServletContext context = config.getServletContext();
//2.获取index.html的本地路径
//index.html的虚拟路径是“/index.html”,其中“/”表示当前Web应用的根目录,
//即WebContent目录
String realPath = context.getRealPath(“/index.html”);
//realPath=D:\DevWorkSpace\MyWorkSpace.metadata.plugins\
//org.eclipse.wst.server.core\tmp0\wtpwebapps\MyServlet\index.html
System.out.println(“realPath=”+realPath);
} - ③ 获取WEB应用程序的全局初始化参数(基本不用) - 设置Web应用初始化参数的方式是在web.xml的根标签下加入如下代码 -


ParamName
ParamValue

- 获取Web应用初始化参数 - @Override
public void init(ServletConfig config) throws ServletException {
//1.获取ServletContext对象
ServletContext application = config.getServletContext();
//2.获取Web应用初始化参数
String paramValue = application.getInitParameter(“ParamName”);
System.out.println(“全局初始化参数paramValue=”+paramValue);
} - ④ 作为域对象共享数据 - 作为最大的域对象在整个项目的不同web资源内共享数据。 - JavaWEB葵花宝典 - 图67 -
- 其中, - setAttribute(key,value):以后可以在任意位置取出并使用 - getAttribute(key):取出设置的value值 ## 六、 Servlet技术体系 ### 6.1 Servlet接口 JavaWEB葵花宝典 - 图68 ### 6.2 Servlet接口的常用实现类 - 为什么要扩展Servlet接口? - 封装不常用方法 - 实现类体系 - GenericServlet实现Servlet接口 - HttpServlet继承GenericServlet - 创建Servlet的最终方式 - 继承HttpServlet JavaWEB葵花宝典 - 图69 #### 6.2.1 GenericServlet抽象类 JavaWEB葵花宝典 - 图70 - GenericServlet对Servlet功能进行了封装和完善,重写了init(ServletConfig config)方法,用来获取ServletConfig对象。此时如果GenericServlet的子类(通常是自定义Servlet)又重写了init(ServletConfig config)方法有可能导致ServletConfig对象获取不到,所以子类不应该重写带参数的这个init()方法。 - 如果想要进行初始化操作,可以重写GenericServlet提供的无参的init()方法,这样就不会影响ServletConfig对象的获取。 - 将service(ServletRequest req,ServletResponse res)保留为抽象方法,让使用者仅关心业务实现即可。 JavaWEB葵花宝典 - 图71 #### 6.2.2 HttpServlet抽象类 JavaWEB葵花宝典 - 图72 JavaWEB葵花宝典 - 图73 - 专门用来处理Http请求的Servlet。 - 对GenericServlet进行进一步的封装和扩展,在service(ServletRequest req, ServletResponse res)方法中,将ServletRequest和ServletResponse转换为HttpServletRequest和HttpServletResponse,根据不同HTTP请求类型调用专门的方法进行处理。 - 今后在实际使用中继承HttpServlet抽象类创建自己的Servlet实现类即可。重写doGet(HttpServletRequest req, HttpServletResponse resp)和doPost(HttpServletRequest req, HttpServletResponse resp)方法实现请求处理,不再需要重写service(ServletRequest req, ServletResponse res)方法了。 - 又因为我们业务中get,post的处理方式又都是一样的,所以我们只需要写一种方法即可,使用另外一种方法调用我们写好的doXXX方法。web.xml配置与之前相同。 - //处理浏览器的get请求
doGet(HttpServletRequest request, HttpServletResponse response){
//业务代码
}
//处理浏览器的post请求
doPost(HttpServletRequest request, HttpServletResponse response){
doGet(request, response);
} ## 七、 其它几个重要的接口 ### 7.1 HttpServletRequest接口 - 该接口是ServletRequest接口的子接口,封装了HTTP请求的相关信息。 - 浏览器请求服务器时会封装请求报文交给服务器,服务器接受到请求会将请求报文解析生成request对象。 - 由Servlet容器创建其实现类对象并传入service(HttpServletRequest req, HttpServletResponse res)方法中。 - 以下我们所说的HttpServletRequest对象指的是容器提供的HttpServletRequest实现类对象。 HttpServletRequest对象的主要功能有:
#### 7.1.1 获取请求参数 - 什么是请求参数? - 请求参数就是浏览器向服务器提交的数据。 - 浏览器向服务器如何发送数据? - ① 附在url后面(和get请求一致,拼接的形式就行请求数据的绑定),如: - http://localhost:8080/MyServlet/MyHttpServlet?userId=20 - ② 通过表单提交 -

你喜欢的足球队


巴西
德国
荷兰

- 使用HttpServletRequest对象获取请求参数 - //一个name对应一个值
String userId = request.getParameter(“userId”); - //一个name对应一组值
String[] soccerTeams = request.getParameterValues(“soccerTeam”);
for(int i = 0; i < soccerTeams.length; i++){
System.out.println(“team “+i+”=”+soccerTeams[i]);
} #### 7.1.2 获取url地址参数 String path = request.getContextPath();//重要
System.out.println(“上下文路径:”+path);
System.out.println(“端口号:”+request.getServerPort());
System.out.println(“主机名:”+request.getServerName());
System.out.println(“协议:”+request.getScheme());
#### 7.1.3 获取请求头信息 JavaWEB葵花宝典 - 图74 String header = request.getHeader(“User-Agent”);
System.out.println(“user-agent:”+header);
String referer = request.getHeader(“Referer”);
System.out.println(“上个页面的地址:”+referer);//登录失败,返回登录页面让用户继续登录
#### 7.1.4 请求的转发 将请求转发给另外一个URL地址,参见第7章-请求的转发与重定向。
//获取请求转发对象
RequestDispatcher dispatcher = request.getRequestDispatcher(“success.html”);
dispatcher.forward(request, response);//发起转发
#### 7.1.5 向请求域中保存数据 //将数据保存到request对象的属性域中
request.setAttribute(“attrName”, “attrValueInRequest”);
//两个Servlet要想共享request对象中的数据,必须是转发的关系
request.getRequestDispatcher(“/ReceiveServlet”).forward(request, response);
//从request属性域中获取数据
Object attribute = request.getAttribute(“attrName”);
System.out.println(“attrValue=”+attribute);
### 7.2 HttpServletResponse接口 - 该接口是ServletResponse接口的子接口,封装了服务器针对于HTTP响应的相关信息。(暂时只有服务器的配置信息,没有具体的和响应体相关的内容) - 由Servlet容器创建其实现类对象,并传入service(HttpServletRequest req, HttpServletResponse res)方法中。 - 后面我们所说的HttpServletResponse对象指的是容器提供的HttpServletResponse实现类对象。 HttpServletResponse对象的主要功能有:
#### 7.2.1 使用PrintWriter对象向浏览器输出数据 //通过PrintWriter对象向浏览器端发送响应信息
PrintWriter writer = res.getWriter();
writer.write(“Servlet response”);
writer.close(); - 写出的数据可以是页面、页面片段、字符串等 - 当写出的数据包含中文时,浏览器接收到的响应数据就可能有乱码。为了避免乱码,可以使用Response对象在向浏览器输出数据前设置响应头。 #### 7.2.2 设置响应头 - 响应头就是浏览器解析页面的配置。比如:告诉浏览器使用哪种编码和文件格式解析响应体内容 response.setHeader(“Content-Type”, “text/html;charset=UTF-8”); - 设置好以后,会在浏览器的响应报文中看到设置的响应头中的信息。 #### 7.2.3 重定向请求 - 实现请求重定向,参见第8章-请求的转发与重定向。 - 举例:用户从login.html页面提交登录请求数据给LoginServlet处理。如果账号密码正确,需要让用户跳转到成功页面,通过servlet向响应体中写入成功页面过于复杂,通过重定向将成功页面的地址交给浏览器并设置响应状态码为302,浏览器会自动进行跳转。 //注意路径问题,加上/会失败,会以主机地址为起始,重定向一般需要加上项目名
response.sendRedirect(“success.html”);
## 八、 请求的转发与重定向 请求的转发与重定向是web应用页面跳转的主要手段,在Web应用中使用非常广泛。所以我们一定要搞清楚他们的区别。
JavaWEB葵花宝典 - 图75 ### 8.1 请求的转发 JavaWEB葵花宝典 - 图76 - 第一个Servlet接收到了浏览器端的请求,进行了一定的处理,然后没有立即对请求进行响应,而是将请求“交给下一个Servlet”继续处理,下一个Servlet处理完成之后对浏览器进行了响应。在服务器内部将请求“交给”其它组件继续处理就是请求的转发。对浏览器来说,一共只发了一次请求,服务器内部进行的“转发”浏览器感觉不到,同时浏览器地址栏中的地址不会变成“下一个Servlet”的虚拟路径。 - HttpServletRequest代表HTTP请求,对象由Servlet容器创建。转发的情况下,两个Servlet可以共享同一个Request对象中保存的数据。 - 当需要将后台获取的数据传送到JSP上显示的时候,就可以先将数据存放到Request对象中,再转发到JSP从属性域中获取。此时由于是“转发”,所以它们二者共享Request对象中的数据。 - 转发的情况下,可以访问WEB-INF下的资源。 - 转发以“/”开始表示项目根路径,重定向以”/”开始表示主机地址。 - 功能: - 获取请求参数 - 获取请求路径即URL地址相关信息 - 在请求域中保存数据 - 转发请求 - 代码举例 protected void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
//1.使用RequestDispatcher对象封装目标资源的虚拟路径
RequestDispatcher dispatcher = request.getRequestDispatcher(“/index.html”);
//2.调用RequestDispatcher对象的forward()方法“前往”目标资源
//[注意:传入的参数必须是传递给当前Servlet的service方法的
//那两个ServletRequest和ServletResponse对象]
dispatcher.forward(request, response);
}
### 8.2 请求的重定向 JavaWEB葵花宝典 - 图77 - 第一个Servlet接收到了浏览器端的请求,进行了一定的处理,然后给浏览器一个特殊的响应消息,这个特殊的响应消息会通知浏览器去访问另外一个资源,这个动作是服务器和浏览器自动完成的。整个过程中浏览器端会发出两次请求,且在浏览器地址栏里面能够看到地址的改变,改变为下一个资源的地址。 - 重定向的情况下,原Servlet和目标资源之间就不能共享请求域数据了。 - HttpServletResponse代表HTTP响应,对象由Servlet容器创建。 - 功能: - 向浏览器输出数据 - 重定向请求 - 重定向的响应报文的头 - HTTP/1.1 302 Found
Location: success.html - 应用: - 用户从login.html页面提交登录请求数据给LoginServlet处理。 - 如果账号密码正确,需要让用户跳转到成功页面,通过servlet向响应体中写入成功页面过于复杂,通过重定向将成功页面的地址交给浏览器并设置响应状态码为302,浏览器会自动进行跳转 - 代码举例: protected void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
//1.调用HttpServletResponse对象的sendRedirect()方法
//2.传入的参数是目标资源的虚拟路径
response.sendRedirect(“index.html”);
}
### 8.3 对比请求的转发与重定向 | | 转发 | 重定向 | | —- | —- | —- | | 浏览器感知 | 在服务器内部完成,浏览器感知不到 | 服务器以302状态码通知浏览器访问新地址,浏览器有感知 | | 浏览器地址栏 | 不改变 | 改变 | | 整个过程发送请求次数 | 一次 | 两次 | | 执行效率 | 效率高 | 效率低 | | API(或发起者) | Request对象 | Response对象 | | 能否共享request对象数据 | 能 | 否 | | WEB-INF下的资源 | 能访问 | 不能访问 | | 目标资源 | 必须是当前web应用中的资源 | 不局限于当前web应用 | 说明1:默认情况下,浏览器是不能访问服务器web-inf下的资源的,而服务器是可以访问的。
说明2:浏览器默认的绝对路径:http://localhost:8080/
服务器项目的代码中的绝对路径:http://localhost:8080/项目名/
## 九、 请求与响应中的字符编码设置 ### 9.1 字符编码问题 - 我们web程序在接收请求并处理过程中,如果不注意编码格式及解码格式,很容易导致中文乱码,引起这个问题的原因到底在哪里?如何解决?我们这个小节将会讨论此问题。 - 说到这个问题我们先来说一说字符集。 - 什么是字符集,就是各种字符的集合,包括汉字,英文,标点符号等等。各国都有不同的文字、符号。这些文字符号的集合就叫字符集。 - 现有的字符集ASCII、GB2312、BIG5、GB18030、Unicode、UTF-8、ISO-8859-1等 - 这些字符集,集合了很多的字符,然而,字符要以二进制的形式存储在计算机中,我们就需要对其进行编码,将编码后的二进制存入。取出时我们就要对其解码,将二进制解码成我们之前的字符。这个时候我们就需要制定一套编码解码标准。否则就会导致出现混乱,也就是我们的乱码。 ### 9.2 编码与解码 - 编码:将字符转换为二进制数 | 汉字 | 编码方式 | 编码 | 二进制 | | —- | —- | —- | —- | | ‘中’ | GB2312 | D6D0 | 1101 0110-1101 0000 | | ‘中’ | UTF-16 | 4E2D | 0100 1110-0010 1101 | | ‘中’ | UTF-8 | E4B8AD | 1110 0100- 1011 1000-1010 1101 | - 解码:将二进制数转换为字符 1110 0100-1011 1000-1010 1101 → E4B8AD → ’中’ - 乱码:一段文本,使用A字符集编码,使用B字符集解码,就会产生乱码。所以解决乱码问题的根本方法就是统一编码和解码的字符集。 JavaWEB葵花宝典 - 图78 ### 9.3 解决请求乱码问题 解决乱码的方法:就是统一字符编码。
JavaWEB葵花宝典 - 图79 #### 9.3.1 GET请求 - GET请求参数是在地址后面的。我们需要修改tomcat的配置文件。需要在server.xml文件修改Connector标签,添加URIEncoding=”utf-8”属性。 JavaWEB葵花宝典 - 图80 - 一旦配置好以后,可以解决当前工作空间中所有的GET请求的乱码问题。 #### 9.3.2 POST请求 - post请求提交了中文的请求体,服务器解析出现问题。 - 解决方法:在获取参数值之前,设置请求的解码格式,使其和页面保持一致。 - request.setCharacterEncoding(“utf-8”); - POST请求乱码问题的解决,只适用于当前的操作所在的类中。不能类似于GET请求一样统一解决。因为请求体有可能会上传文件。不一定都是中文字符。 ### 9.4 解决响应乱码问题 - 向浏览器发送响应的时候,要告诉浏览器,我使用的字符集是哪个,浏览器就会按照这种方式来解码。如何告诉浏览器响应内容的字符编码方案。很简单。 - 解决方法一: - response.setHeader(“Content-Type”, “text/html;charset=utf-8”); - 解决方法二 : - response.setContentType(“text/html;charset=utf-8”); - 说明:有的人可能会想到使用response.setCharacterEncoding(“utf-8”),设置reponse对象将UTF-8字符串写入到响应报文的编码为UTF-8。只这样做是不行的,还必须手动在浏览器中设置浏览器的解析用到的字符集。 ## 十、 Web应用路径设置 问题再现:
① 创建Web应用Path,目录结构如图所示
JavaWEB葵花宝典 - 图81 ② 在a.html中有超链接To b.html
③ 如果先直接访问a.html,再通过超链接转到b.html没有问题。
④ 如果先通过TestServlet转发到a.html,则浏览器地址栏会变成
http://localhost:8989/Path/TestServlet
此时再点击超链接To b.html就会发生问题,找不到b.html。
如何解决?
原因是超链接
To b.html使用的是相对路径,浏览器进行解析时,只能以当前浏览器地址栏里的路径为基准。例如,当前浏览器地址栏里的内容是:http://localhost:8989/Path/TestServlet
那么经过浏览器解析后b.html的访问地址就成了:http://localhost:8989/Path/TestServletb.html这显然无法访问到b.html。
完整的url构成如下图:
JavaWEB葵花宝典 - 图82 相对路径和绝对路径
相对路径:虚拟路径如果不以“/”开始,就是相对路径,浏览器会以当前资源所在的虚拟路径为基准对相对路径进行解析,从而生成最终的访问路径。此时如果通过转发进入其他目录,再使用相对路径访问资源就会出错。所以为了防止路径出错,我们经常将相对路径转化为绝对路径的形式进行请求。
绝对路径:虚拟路径以“/”开始,就是绝对路径。 ① 在服务器端:虚拟路径最开始的“/”表示当前Web应用的根目录。只要是服务端解析的绝对路径,都是以web根目录为起始的。由服务器解析的路径包括:<1> web.xml的配置路径、<2>request转发的路径。 ② 在浏览器端:虚拟路径最开始的“/”表示当前主机地址。 例如:链接地址“/Path/dir/b.html”经过浏览器解析后为: 相当于http://localhost:8989/Path/dir/b.html 由浏览器解析的路径包括: <1>重定向操作:response.sendRedirect(“/xxx”) <2>所有HTML标签:
、link、img、script等 这些最后的访问路径都是 http://localhost:8989/xxx
所以我们可以看出,如果是浏览器解析的路径,我们必须加上项目名称才可以正确的指向资源。http://localhost:8989/Path/xxx
<1>重定向操作:
response.sendRedirect(request.getContextPath()+”/xxx”);
<2>所有HTML标签:; <form action=“/项目名/xxx”> - 在浏览器端,除了使用绝对路径之外,我们还可以使用base标签+相对路径的方式来确定资源的访问有效。 - base标签影响当前页面中的所有相对路径,不会影响绝对路径。相当于给相对路径设置了一个基准地址。 - 习惯上在html的标签内,声明:

接着html中的路径就可以使用相对路径的方式来访问。比如:

base+相对路径



1.html

a/3.html


PathServlet
### 精简版 ① 建议使用绝对路径
在路径前添加/
② /的含义
浏览器:/ 当前主机下 —-> localhost:8080/
页面上所有路径和重定向
服务器:/ 当前项目下 —-> localhost:8080/projectName
web.xml和转发 ## 第九章 Thymeleaf ### 1. 学习目标 - 掌握MVC - 了解Thymeleaf的简介 - 掌握引入Thymeleaf - 掌握Thymeleaf的入门案例 ### 2. 内容讲解 #### 2.1 MVC ##### 2.1.1 为什么需要MVC 我们之前在书城项目第二阶段做登录的时候,曾经提出过优化登录失败后的处理,曾经编写过下面这段代码
JavaWEB葵花宝典 - 图83 这段代码虽然说可以实现在登录失败之后跳转回到登录页面,并且展示失败信息,但是代码实在是太恶心了,根本没法维护,所以我们需要将视图展示抽取出来,单独作为一个View视图层
但是我们如果只使用HTML作为视图的话,它是无法展示动态数据的,所以我们对HTML的新的期待:既能够正常显示页面,又能在页面中包含动态数据部分。而动态数据单靠HTML本身是无法做到的,所以此时我们需要引入服务器端动态视图模板技术。
##### 2.1.2 MVC概念 M:Model模型 User
V:View视图 最终网页显示的效果(页面内容+动态数据)
C:Controller控制器 Servlet
MVC是在表述层开发中运用的一种设计理念。主张把封装数据的『模型』显示用户界面的『视图』协调调度的『控制器』分开。
好处: - 进一步实现各个组件之间的解耦 - 让各个组件可以单独维护 - 将视图分离出来以后,我们后端工程师和前端工程师的对接更方便 ##### 2.1.3 MVC和三层架构之间关系 JavaWEB葵花宝典 - 图84 #### 2.2 Thymeleaf的简介 ##### 2.2.1 Thymeleaf的概念 Thymeleaf是一款用于渲染XML/XHTML/HTML5内容的模板引擎。类似JSP,Velocity,FreeMaker等, 它也可以轻易的与Spring MVC等Web框架进行集成作为Web应用的模板引擎。它的主要作用是在静态页面上渲染显示动态数据
##### 2.2.2 Thymeleaf的优势 - SpringBoot官方推荐使用的视图模板技术,和SpringBoot完美整合。 - 不经过服务器运算仍然可以直接查看原始值,对前端工程师更友好。 <!DOCTYPE html>






Original Value




##### 2.2.3 物理视图和逻辑视图 ###### 2.2.3.1 物理视图 在Servlet中,将请求转发到一个HTML页面文件时,使用的完整的转发路径就是物理视图。JavaWEB葵花宝典 - 图85
/pages/user/login_success.html
如果我们把所有的HTML页面都放在某个统一的目录下,那么转发地址就会呈现出明显的规律:
/pages/user/login.html /pages/user/login_success.html /pages/user/regist.html /pages/user/regist_success.html
……
路径的开头都是:/pages/user/
路径的结尾都是:.html
所以,路径开头的部分我们称之为视图前缀,路径结尾的部分我们称之为视图后缀。
###### 2.2.3.2 逻辑视图 ### 逻辑视图 物理视图=视图前缀+逻辑视图+视图后缀
上面的例子中: | 视图前缀 | 逻辑视图 | 视图后缀 | 物理视图 | | —- | —- | —- | —- | | /pages/user/ | login | .html | /pages/user/login.html | | /pages/user/ | login_success | .html | /pages/user/login_success.html | #### 2.3 Thymeleaf的入门案例 ##### 2.3.1 加入jar包 JavaWEB葵花宝典 - 图86 ##### 2.3.2 配置上下文参数 JavaWEB葵花宝典 - 图87 物理视图=视图前缀+逻辑视图+视图后缀


view-prefix
/WEB-INF/view/


view-suffix
.html

说明:param-value中设置的前缀、后缀的值不是必须叫这个名字,可以根据实际情况和需求进行修改。
为什么要放在WEB-INF目录下?
原因:WEB-INF目录不允许浏览器直接访问,所以我们的视图模板文件放在这个目录下,是一种保护。以免外界可以随意访问视图模板文件。
访问WEB-INF目录下的页面,都必须通过Servlet转发过来,简单说就是:不经过Servlet访问不了。
这样就方便我们在Servlet中检查当前用户是否有权限访问。
那放在WEB-INF目录下之后,重定向进不去怎么办?
重定向到Servlet,再通过Servlet转发到WEB-INF下。
##### 2.3.3 创建Servlet基类 这个类大家直接复制粘贴即可,将来使用框架后,这些代码都将被取代。
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.WebContext;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.ServletContextTemplateResolver; import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException; public class ViewBaseServlet extends HttpServlet { private TemplateEngine templateEngine; @Override
public void init() throws ServletException { // 1.获取ServletContext对象
ServletContext servletContext = this.getServletContext(); // 2.创建Thymeleaf解析器对象
ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(servletContext); // 3.给解析器对象设置参数
// ①HTML是默认模式,明确设置是为了代码更容易理解
templateResolver.setTemplateMode(TemplateMode.HTML); // ②设置前缀
String viewPrefix = servletContext.getInitParameter(“view-prefix”); templateResolver.setPrefix(viewPrefix); // ③设置后缀
String viewSuffix = servletContext.getInitParameter(“view-suffix”); templateResolver.setSuffix(viewSuffix); // ④设置缓存过期时间(毫秒)
templateResolver.setCacheTTLMs(60000L); // ⑤设置是否缓存
templateResolver.setCacheable(true); // ⑥设置服务器端编码方式
templateResolver.setCharacterEncoding(“utf-8”); // 4.创建模板引擎对象
templateEngine = new TemplateEngine(); // 5.给模板引擎对象设置模板解析器
templateEngine.setTemplateResolver(templateResolver); } protected void processTemplate(String templateName, HttpServletRequest req, HttpServletResponse resp) throws IOException {
// 1.设置响应体内容类型和字符集
resp.setContentType(“text/html;charset=UTF-8”); // 2.创建WebContext对象
WebContext webContext = new WebContext(req, resp, getServletContext()); // 3.处理模板数据
templateEngine.process(templateName, webContext, resp.getWriter());
}
}
##### 2.3.4 入门案例代码 ###### 2.3.4.1 创建index.html文件 JavaWEB葵花宝典 - 图88 ###### 2.3.4.2 index.html编写超链接访问Servlet 初步测试Thymeleaf
###### 2.3.4.2 创建Servlet JavaWEB葵花宝典 - 图89
testThymeleafServlet
com.atguigu.servlet.TestThymeleafServlet


testThymeleafServlet
/testThymeleaf

###### 2.3.4.3 修改Servlet让其继承ViewBaseServlet JavaWEB葵花宝典 - 图90 ###### 2.3.4.4 在doPost()方法中跳转到Thymeleaf页面 package com.atguigu.servlet; import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException; /**
@author chenxin
日期2021-05-13 09:15
/
public class TestThymeleafServlet extends ViewBaseServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
} @Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setAttribute(“username”,”奥巴马”);
//请求转发跳转到/WEB-INF/view/target.html
processTemplate(“target”,request,response);
}
}
###### 2.3.4.5 Thymeleaf页面代码 <!DOCTYPE html>






这里要显示一个动态的username




## 2 Thymeleaf的基本语法 ### 1. 学习目标 - 掌握th名称空间 - 掌握表达式语法 - 掌握访问域对象 - 获取请求参数 - 掌握内置对象 - 掌握OGNL表达式 - 掌握分支和迭代 - 掌握使用Thymeleaf包含其它文件 - 使用Thymeleaf练习CRUD ### 2. 内容讲解 #### 2.1 th名称空间 JavaWEB葵花宝典 - 图91 #### 2.2 表达式语法 ##### 2.2.1 修改标签文本值 代码示例:

标签体原始值


###### 2.2.1.1 th:text作用 - 不经过服务器解析,直接用浏览器打开HTML文件,看到的是『标签体原始值』 - 经过服务器解析,Thymeleaf引擎根据th:text属性指定的『标签体新值』去替换『标签体原始值』 ###### 2.2.1.2 字面量和变量 『字面量』是一个经常会遇到的概念,我们可以对照『变量』来理解它的含义。
// a是变量,100是字面量
int a = 100;
System.out.println(“a = “ + a); - 变量:变量名字符串本身不是它的值,它指向的才是它的值 - 字面量:它就是字面上的含义,我们从『字面』上看到的直接就是它的值 现在我们在th:text属性中使用的就是『字面量』,它不指代任何其他值。
##### 2.2.2 修改指定属性值 代码示例:

语法:任何HTML标签原有的属性,前面加上『th:』就都可以通过Thymeleaf来设定新值。
##### 2.2.3 解析URL地址 代码示例:

访问index.html
经过解析后得到:
/webday08/index.html
所以@{}的作用是在字符串前附加『上下文路径』
这个语法的好处是:实际开发过程中,项目在不同环境部署时,Web应用的名字有可能发生变化。所以上下文路径不能写死。而通过@{}动态获取上下文路径后,不管怎么变都不怕啦!
###### 2.2.3.1 首页使用URL地址解析 JavaWEB葵花宝典 - 图92 如果我们直接访问index.html本身,那么index.html是不需要通过Servlet,当然也不经过模板引擎,所以index.html上的Thymeleaf的任何表达式都不会被解析。
解决办法:通过Servlet访问index.html,这样就可以让模板引擎渲染页面了:
JavaWEB葵花宝典 - 图93 进一步的好处:
通过上面的例子我们看到,所有和业务功能相关的请求都能够确保它们通过Servlet来处理,这样就方便我们统一对这些请求进行特定规则的限定。
###### 2.2.3.2 给URL地址后面附加请求参数 参照官方文档说明:
JavaWEB葵花宝典 - 图94 #### 2.3 域对象在Thymeleaf中的使用 ##### 2.3.1 回顾域对象 域对象是在服务器中有一定作用域范围的对象,在这个范围内的所有动态资源都能够共享域对象中保存的数据
##### 2.3.2 回顾域对象的类型 ###### 2.3.2.1 请求域 在请求转发的场景下,我们可以借助HttpServletRequest对象内部给我们提供的存储空间,帮助我们携带数据,把数据发送给转发的目标资源。
请求域:HttpServletRequest对象内部给我们提供的存储空间
JavaWEB葵花宝典 - 图95 ###### 2.3.2.2 会话域(还没学) 会话域的范围是一次会话
JavaWEB葵花宝典 - 图96 ###### 2.3.2.3 应用域(全局域) 应用域的范围是整个项目全局
JavaWEB葵花宝典 - 图97 ##### 2.3.3 在Thymeleaf中操作域对象 我们通常的做法是,在Servlet中将数据存储到域对象中,而在使用了Thymeleaf的前端页面中取出域对象中的数据并展示
###### 2.3.3.1 操作请求域 Servlet中代码:
String requestAttrName = “helloRequestAttr”;
String requestAttrValue = “helloRequestAttr-VALUE”; request.setAttribute(requestAttrName, requestAttrValue);
Thymeleaf表达式:

request field value


###### 2.3.3.2 操作会话域 Servlet中代码:
// ①通过request对象获取session对象
HttpSession session = request.getSession(); // ②存入数据
session.setAttribute(“helloSessionAttr”, “helloSessionAttr-VALUE”);
Thymeleaf表达式:

这里显示会话域数据


###### 2.3.3.3 操作应用域 Servlet中代码:
// ①通过调用父类的方法获取ServletContext对象
ServletContext servletContext = getServletContext(); // ②存入数据
servletContext.setAttribute(“helloAppAttr”, “helloAppAttr-VALUE”);
Thymeleaf表达式:

这里显示应用域数据


#### 2.4 获取请求参数 请求参数和请求域中的数据 ##### 2.4.1 获取请求参数的语法 ${param.参数名}
##### 2.4.2 根据一个参数名获取一个参数值 页面代码:

这里替换为请求参数的值


页面显示效果:
JavaWEB葵花宝典 - 图98 ##### 2.4.3 根据一个参数名获取多个参数值 页面代码:

这里替换为请求参数的值


页面显示效果:
JavaWEB葵花宝典 - 图99 如果想要精确获取某一个值,可以使用数组下标。页面代码:

这里替换为请求参数的值


这里替换为请求参数的值


页面显示效果:
JavaWEB葵花宝典 - 图100 #### 2.5 内置对象(了解) ##### 2.5.1 内置对象的概念 所谓内置对象其实就是在Thymeleaf的表达式中可以直接使用的对象
##### 2.5.2 基本内置对象 JavaWEB葵花宝典 - 图101 用法举例:

表达式的基本内置对象


调用#request对象的getContextPath()方法


调用#request对象的getAttribute()方法,读取属性域


基本思路: - 如果不清楚这个对象有哪些方法可以使用,那么就通过getClass().getName()获取全类名,再回到Java环境查看这个对象有哪些方法 - 内置对象的方法可以直接调用 - 调用方法时需要传参的也可以直接传入参数 ##### 2.5.3 公共内置对象 JavaWEB葵花宝典 - 图102 Servlet中将List集合数据存入请求域:
request.setAttribute(“aNotEmptyList”, Arrays.asList(“aaa”,”bbb”,”ccc”));
request.setAttribute(“anEmptyList”, new ArrayList<>());
页面代码:

#list对象isEmpty方法判断集合整体是否为空aNotEmptyList:测试#lists


#list对象isEmpty方法判断集合整体是否为空anEmptyList:测试#lists


公共内置对象对应的源码位置:
JavaWEB葵花宝典 - 图103
images
#### 2.6 OGNL ##### 2.6.1 OGNL的概念 OGNL:Object-Graph Navigation Language对象-图 导航语言
##### 2.6.2 对象图的概念 从根对象触发,通过特定的语法,逐层访问对象的各种属性。
JavaWEB葵花宝典 - 图104 ##### 2.6.3 OGNL语法 ###### 2.6.3.1 起点 在Thymeleaf环境下,${}中的表达式可以从下列元素开始: - 访问属性域的起点 - 请求域属性名 - session - application - param - 内置对象 - request - session - lists - strings ###### 2.6.3.2 属性访问语法 - 访问对象属性:使用getXxx()、setXxx()方法定义的属性 - 对象.属性名 - 访问List集合或数组 - 集合或数组[下标] - 访问Map集合 - Map集合.key - Map集合[‘key’] #### 2.7 分支与迭代 ##### 2.7.1 分支 ###### 2.7.1.1 if和unless 让标记了th:if、th:unless的标签根据条件决定是否显示。
示例的实体类:
package com.atguigu.bean; /*
包名:com.atguigu.bean

@author chenxin
日期2021-05-13 10:58
/
public class Teacher {
private String teacherName; public Teacher() {
} public Teacher(String teacherName) {
this.teacherName = teacherName;
} public String getTeacherName() {
return teacherName;
} public void setTeacherName(String teacherName) {
this.teacherName = teacherName;
}
}
示例的Servlet代码:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 1.创建ArrayList对象并填充
List employeeList = new ArrayList<>(); employeeList.add(new Employee(1, “tom”, 500.00));
employeeList.add(new Employee(2, “jerry”, 600.00));
employeeList.add(new Employee(3, “harry”, 700.00)); // 2.将集合数据存入请求域
request.setAttribute(“employeeList”, employeeList); // 3.调用父类方法渲染视图
super.processTemplate(“list”, request, response);
}
示例的HTML代码:















员工编号 员工姓名 员工工资
抱歉!没有查询到你搜索的数据!
有数据!
有数据!

if配合not关键词和unless配合原表达式效果是一样的,看自己的喜好。
###### 2.7.1.2 switch

测试switch



银牌会员


金牌会员


白金会员


钻石会员



##### 2.7.2 迭代 在迭代过程中,可以参考下面的说明使用迭代状态:
JavaWEB葵花宝典 - 图105

















编号 姓名
教师的集合是空的!!!
这里显示编号 这里显示老师的名字

#### 2.8 Thymeleaf包含其他模板文件 ##### 2.8.1 应用场景 抽取各个页面的公共部分:
JavaWEB葵花宝典 - 图106 ##### 2.8.2 操作步骤 ###### 2.8.2.1 创建页面的公共代码片段 使用th:fragment来给这个片段命名:

被抽取出来的头部内容



###### 2.8.2.2 在需要的页面中进行包含 | 语法 | 效果 | 特点 | | —- | —- | —- | | th:insert | 把目标的代码片段整个插入到当前标签内部 | 它会保留页面自身的标签 | | th:replace | 用目标的代码替换当前标签 | 它不会保留页面自身的标签 | | th:include | 把目标的代码片段去除最外层标签,然后再插入到当前标签内部 | 它会去掉片段外层标记,同时保留页面自身标记 | 页面代码举例:


div标签的原始内容

div标签的原始内容


div标签的原始内容

第十章 会话

1. 学习目标

  • 了解为什么需要会话控制
  • 了解会话的范围
  • 掌握使用Cookie
  • 掌握使用Session

2. 内容讲解

2.1 为什么需要会话控制

JavaWEB葵花宝典 - 图107
images
保持用户登录状态,就是当用户在登录之后,会在服务器中保存该用户的登录状态,当该用户后续访问该项目中的其它动态资源(Servlet或者Thymeleaf)的时候,能够判断当前是否是已经登录过的。而从用户登录到用户退出登录这个过程中所发生的所有请求,其实都是在一次会话范围之内

2.2 域对象的范围

2.2.1 应用域的范围

JavaWEB葵花宝典 - 图108

整个项目部署之后,只会有一个应用域对象,所有客户端都是共同访问同一个应用域对象,在该项目的所有动态资源中也是共用一个应用域对象

2.2.2 请求域的范围

JavaWEB葵花宝典 - 图109 每一次请求都有一个请求域对象,当请求结束的时候对应的请求域对象也就销毁了

2.3 会话域的范围

JavaWEB葵花宝典 - 图110

会话域是从客户端连接上服务器开始,一直到客户端关闭,这一整个过程中发生的所有请求都在同一个会话域中;而不同的客户端是不能共用会话域的

2.3 Cookie技术

2.3.1 Cookie的概念

Cookie是一种客户端的会话技术,它是服务器存放在浏览器的一小份数据,浏览器以后每次访问该服务器的时候都会将这小份数据携带到服务器去。
JavaWEB葵花宝典 - 图111

2.3.2 Cookie的作用
  1. 在浏览器中存放数据
  2. 将浏览器中存放的数据携带到服务器

2.3.3 Cookie的应用场景

1.记住用户名 当我们在用户名的输入框中输入完用户名后,浏览器记录用户名,下一次再访问登录页面时,用户名自动填充到用户名的输入框.
2.保存电影的播放进度
在网页上播放电影的时候,如果中途退出浏览器了,下载再打开浏览器播放同一部电影的时候,会自动跳转到上次退出时候的进度,因为在播放的时候会将播放进度保存到cookie中

2.3.4 Cookie的入门案例

2.3.4.1 目标

实现在ServletDemo01和ServletDemo02之间共享数据,要求在会话域范围内共享

2.3.4.2 Cookie相关的API
  • 创建一个Cookie对象(cookie只能保存字符串数据。且不能保存中文)

new Cookie(String name,String value);

  • 把cookie写回浏览器

response.addCookie(cookie);

  • 获得浏览器带过来的所有Cookie:

request.getCookies() ; //得到所有的cookie对象。是一个数组,开发中根据key得到目标cookie

  • cookie的 API

cookie.getName() ; //返回cookie中设置的key
cookie.getValue(); //返回cookie中设置的value

2.3.4.2 ServletDemo01代码

在ServletDemo01中创建Cookie数据并响应给客户端
public class ServletDemo01 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}

@Override<br />    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {<br />        //1. 创建一个cookie对象,用于存放键值对<br />        Cookie cookie = new Cookie("cookie-message","hello-cookie");

    //2. 将cookie添加到response中<br />        //底层是通过一个名为"Set-Cookie"的响应头携带到浏览器的<br />        response.addCookie(cookie);<br />    }<br />}<br />![](https://cdn.nlark.com/yuque/0/2021/png/25621085/1640875687761-fd858bcd-4cc3-4c71-bb17-3a0e54068cff.png#)

2.3.4.2 浏览器发送请求携带Cookie

这里不需要我们操作,浏览器会在给服务器发送请求的时候,将cookie通过请求头自动携带到服务器
JavaWEB葵花宝典 - 图112

2.3.4.3 ServletDemo02获取Cookie数据的代码

public class ServletDemo02 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}

@Override<br />    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {<br />        //1. 从请求中取出cookie<br />        //底层是由名为"Cookie"的请求头携带的<br />        Cookie[] cookies = request.getCookies();

    //2. 遍历出每一个cookie<br />        if (cookies != null) {<br />            for (Cookie cookie : cookies) {<br />                //匹配cookie的name<br />                if (cookie.getName().equals("cookie-message")) {<br />                    //它就是我们想要的那个cookie<br />                    //我们就获取它的value<br />                    String value = cookie.getValue();<br />                    System.out.println("在ServletDemo02中获取str的值为:" + value);<br />                }<br />            }<br />        }<br />    }<br />}<br />

2.3.5 Cookie的时效性

如果我们不设置Cookie的时效性,默认情况下Cookie的有效期是一次会话范围内,我们可以通过cookie的setMaxAge()方法让Cookie持久化保存到浏览器上

  • 会话级Cookie
    • 服务器端并没有明确指定Cookie的存在时间
    • 在浏览器端,Cookie数据存在于内存中
    • 只要浏览器还开着,Cookie数据就一直都在
    • 浏览器关闭,内存中的Cookie数据就会被释放
  • 持久化Cookie
    • 服务器端明确设置了Cookie的存在时间
    • 在浏览器端,Cookie数据会被保存到硬盘上
    • Cookie在硬盘上存在的时间根据服务器端限定的时间来管控,不受浏览器关闭的影响
    • 持久化Cookie到达了预设的时间会被释放

cookie.setMaxAge(int expiry)参数单位是秒,表示cookie的持久化时间,如果设置参数为0,表示将浏览器中保存的该cookie删除

2.3.6 Cookie的path

上网时间长了,本地会保存很多Cookie。对浏览器来说,访问互联网资源时不能每次都把所有Cookie带上。浏览器会使用Cookie的path属性值来和当前访问的地址进行比较,从而决定是否携带这个Cookie。
我们可以通过调用cookie的setPath()方法来设置cookie的path
JavaWEB葵花宝典 - 图113

2.4 Session技术

2.4.1 session概述

session是服务器端的技术。服务器为每一个浏览器开辟一块内存空间,即session对象。由于session对象是每一个浏览器特有的,所以用户的记录可以存放在session对象中

2.4.2 Session的入门案例

2.4.2.1 目标

实现在ServletDemo01和ServletDemo02之间共享数据,要求在会话域范围内共享

2.4.2.2 Session的API介绍
  • request.getSession(); 获得session(如果第一次调用的时候其实是创建session,第一次之后通过sessionId找到session进行使用)
  • Object getAttribute(String name) ;获取值
  • void setAttribute(String name, Object value) ;存储值
  • void removeAttribute(String name) ;移除值

2.4.2.3 在ServletDemo01中往Session域对象存储数据

public class ServletDemo01 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}

@Override<br />    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {<br />        //1. 获取Session对象<br />        HttpSession session = request.getSession();<br />        //2. 往Session对象中存入数据<br />        session.setAttribute("session-message","hello-session");<br />    }<br />}<br />

2.4.3.4 在ServletDemo02中从Session域对象中获取数据

public class ServletDemo02 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}

@Override<br />    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {<br />        //1. 获取Session对象<br />        HttpSession session = request.getSession();<br />        //2. 往Session对象中存入数据<br />        String message = (String)session.getAttribute("session-message");<br />        System.out.println(message);<br />    }<br />}<br />

2.4.3 Session的工作机制

前提:浏览器正常访问服务器

  • 服务器端没调用request.getSession()方法:什么都不会发生
  • 服务器端调用了request.getSession()方法
    • 服务器端检查当前请求中是否携带了JSESSIONID的Cookie
      • 有:根据JSESSIONID在服务器端查找对应的HttpSession对象
        • 能找到:将找到的HttpSession对象作为request.getSession()方法的返回值返回
        • 找不到:服务器端新建一个HttpSession对象作为request.getSession()方法的返回值返回
      • 无:服务器端新建一个HttpSession对象作为request.getSession()方法的返回值返回

JavaWEB葵花宝典 - 图114

代码验证
// 1.调用request对象的方法尝试获取HttpSession对象
HttpSession session = request.getSession();

// 2.调用HttpSession对象的isNew()方法
boolean wetherNew = session.isNew();

// 3.打印HttpSession对象是否为新对象
System.out.println(“wetherNew = “ + (wetherNew?”HttpSession对象是新的”:”HttpSession对象是旧的”));

// 4.调用HttpSession对象的getId()方法
String id = session.getId();

// 5.打印JSESSIONID的值
System.out.println(“JSESSIONID = “ + id);

2.4.4 Session的时效性

2.4.4.1 为什么Session要设置时限

用户量很大之后,Session对象相应的也要创建很多。如果一味创建不释放,那么服务器端的内存迟早要被耗尽。

2.4.4.2 设置时限的难点

从服务器端的角度,很难精确得知类似浏览器关闭的动作。而且即使浏览器一直没有关闭,也不代表用户仍然在使用。

2.4.4.3 服务器端给Session对象设置最大闲置时间
  • 默认值:1800秒

JavaWEB葵花宝典 - 图115

最大闲置时间生效的机制如下:
JavaWEB葵花宝典 - 图116

2.4.4.4 代码验证

// ※测试时效性
// 获取默认的最大闲置时间
int maxInactiveIntervalSecond = session.getMaxInactiveInterval();
System.out.println(“maxInactiveIntervalSecond = “ + maxInactiveIntervalSecond);

// 设置默认的最大闲置时间
session.setMaxInactiveInterval(15);

2.4.4.5 强制Session立即失效

session.invalidate();

第十一章 Filter

1. 目标

  • 了解什么是Filter
  • 了解Filter的作用
  • 掌握Filter的使用
  • 了解Filter的生命周期
  • 掌握过滤器链的使用

2. 内容讲解

2.1 Filter的概念

Filter:一个实现了特殊接口(Filter)的Java类. 实现对请求资源(jsp,servlet,html,)的过滤的功能. 过滤器是一个运行在服务器的程序, 优先于请求资源(Servlet或者jsp,html)之前执行. 过滤器是javaweb技术中最为实用的技术之一

2.2 Filter的作用

Filter的作用是对目标资源(Servlet,jsp)进行过滤,其应用场景有: 登录权限检查,解决网站乱码,过滤敏感字符等等

2.3 Filter的入门案例

2.3.1 案例目标

实现在请求到达ServletDemo01之前解决请求参数的中文乱码

2.3.2 代码实现

2.3.2.1 创建ServletDemo01

web.xml代码

servletDemo01
com.atguigu.ServletDemo01


servletDemo01
/ServletDemo01

ServletDemo01代码
package com.atguigu.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/*
@author chenxin
日期2021-05-18 08:53
/
public class ServletDemo01 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}

@Override<br />    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {<br />        String username = request.getParameter("username");<br />        System.out.println("ServletDemo01接收到了一个请求..."+username);<br />    }<br />}<br />前端页面代码<br /><!DOCTYPE html><br /><html lang="en"><br /><head><br />    <meta charset="UTF-8"><br />    <title>首页</title><br /></head><br /><body><br />    <form action="/webday12/demo01" method="post"><br />        用户名<input type="text" name="username"/><br/><br />        <input type="submit"/><br />    </form><br /></body><br /></html><br />如果此时没有Filter,那么客户端发送的请求直接到达ServletDemo01,中文请求参数就会发生乱码<br />

2.3.2.2 创建EncodingFilter

web.xml代码

encodingFilter
com.atguigu.filter.EncodingFilter


encodingFilter

/demo01

EncodingFilter代码
package com.atguigu.filter;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/*
@author chenxin
日期2021-05-18 08:56
编写过滤器的步骤:
1. 写一个类实现Filter接口,并且重写方法
2. 在web.xml中配置该过滤器的拦截路径
*/
public class EncodingFilter implements Filter {
@Override
public void destroy() {

}

@Override<br />    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {<br />        //解决请求参数的乱码<br />        HttpServletRequest request = (HttpServletRequest) req;<br />        request.setCharacterEncoding("UTF-8");

    //每次有请求被当前filter接收到的时候,就会执行doFilter进行过滤处理<br />        System.out.println("EncodingFilter接收到了一个请求...");

    //这句代码表示放行<br />        chain.doFilter(req, resp);<br />    }

@Override<br />    public void init(FilterConfig config) throws ServletException {

}

}

2.4 Filter的生命周期

2.4.1 回顾Servlet生命周期

2.4.1.1 Servlet的创建时机

Servlet默认在第一次接收请求的时候创建,我们可以通过标签配置Servlet在服务器启动的时候创建

2.4.1.2 Servlet的销毁时机

Servlet会在服务器关闭或者将项目从服务器上移除的时候销毁

2.4.2 Filter的生命周期和生命周期方法
生命周期阶段 执行时机 生命周期方法
创建对象 Web应用启动时 init方法,通常在该方法中做初始化工作
拦截请求 接收到匹配的请求 doFilter方法,通常在该方法中执行拦截过滤
销毁 Web应用卸载前 destroy方法,通常在该方法中执行资源释放

2.5 过滤器匹配规则

2.5.1 过滤器匹配的目的

过滤器匹配的目的是指定当前过滤器要拦截哪些资源

2.5.2 四种匹配规则

2.5.2.1 精确匹配

指定被拦截资源的完整路径:



FilterDemo01

<!-- 通过请求地址模式来设置要拦截的资源 --><br />    <url-pattern>/demo01</url-pattern><br /></filter-mapping><br />上述例子表示要拦截映射路径为/demo01的这个资源<br />

2.5.2.2 模糊匹配

相比较精确匹配,使用模糊匹配可以让我们创建一个Filter就能够覆盖很多目标资源,不必专门为每一个目标资源都创建Filter,提高开发效率。
在我们配置了url-pattern为/user/*之后,请求地址只要是/user开头的那么就会被匹配。

Target02Filter

<!-- 模糊匹配:前杠后星 --><br />    <!--<br />        /user/demo01<br />        /user/demo02<br />        /user/demo03<br />        /demo04<br />    --><br />    <url-pattern>/user/*</url-pattern><br /></filter-mapping><br />极端情况:/*匹配所有请求<br />

2.5.2.3 扩展名匹配


Target04Filter
com.atguigu.filter.filter.Target04Filter


Target04Filter
*.png

上述例子表示拦截所有以.png结尾的请求

2.5.2.4 匹配Servlet名称


Target05Filter

<!-- 根据Servlet名称匹配 --><br />    <servlet-name>Target01Servlet</servlet-name><br /></filter-mapping><br />

2.6 过滤器链

2.6.1 过滤链的概念

一个请求可能被多个过滤器所过滤,只有当所有过滤器都放行,请求才能到达目标资源,如果有某一个过滤器没有放行,那么请求则无法到达后续过滤器以及目标资源,多个过滤器组成的链路就是过滤器链

2.6.2 过滤器链的顺序

过滤器链中每一个Filter执行的顺序是由web.xml中filter-mapping配置的顺序决定的。

2.6.3 过滤器链案例

2.6.3.1 创建ServletDemo01

web.xml代码

servletDemo01
com.atguigu.ServletDemo01


servletDemo01
/ServletDemo01

ServletDemo01代码
public class ServletDemo01 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}

@Override<br />    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {<br />        System.out.println("ServletDemo01接收到了请求...");<br />    }<br />}<br />

2.6.3.2 创建多个Filter拦截Servlet


TargetChain03Filter
/Target05Servlet


TargetChain02Filter
/Target05Servlet


TargetChain01Filter
/Target05Servlet

2 扩展案例: 使用Filter过滤非法字符

非法字符过滤案例V1版本

1. 目标

判断评论内容中是否包含某个固定的非法字符串,如果包含则请求无法到达CommentServlet

2. 代码实现

前端页面代码
<!DOCTYPE html>







评论内容




EncodingFilter的代码,用于解决乱码
package com.atguigu.filter;

import javax.servlet.*;
import java.io.IOException;

/*
@author chenxin
日期2021-05-18 10:19
/
public class EncodingFilter implements Filter {
@Override
public void destroy() {
}

@Override<br />    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {<br />        //解决乱码<br />        req.setCharacterEncoding("UTF-8");<br />        resp.setContentType("text/html;charset=UTF-8");

    chain.doFilter(req, resp);<br />    }

@Override<br />    public void init(FilterConfig config) throws ServletException {

}

}
IllegalFilter的代码,用于过滤非法字符
package com.atguigu.filter;

import javax.servlet.*;
import java.io.IOException;

/*
@author chenxin
日期2021-05-18 10:22
/
public class IllegalCharFilter implements Filter {
@Override
public void destroy() {
}

@Override<br />    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {<br />        //1. 获取客户端提交的评论内容<br />        String content = req.getParameter("content");<br />        if (content != null) {<br />            //2. 判断content中是否包含非法字符<br />            if (content.contains("你大爷的")) {<br />                resp.getWriter().write("评论内容中包含非法字符,评论发布失败!!!");<br />                return;<br />            }<br />        }<br />        chain.doFilter(req, resp);<br />    }

@Override<br />    public void init(FilterConfig config) throws ServletException {

}

}
CommentServlet的代码,用于发表评论
package com.atguigu.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/*
@author chenxin
日期2021-05-18 10:17
/
public class CommentServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}

@Override<br />    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {<br />        //1. 获取评论内容<br />        String content = request.getParameter("content");<br />        //2. 向客户端输出评论内容<br />        response.getWriter().write("恭喜你评论成功,评论内容是:"+content);<br />    }<br />}<br />web.xml中的配置<br /><?xml version="1.0" encoding="UTF-8"?><br /><web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"<br />         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"<br />         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee [http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"](http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd%22)<br />         version="4.0"><br />    <filter><br />        <filter-name>EncodingFilter</filter-name><br />        <filter-class>com.atguigu.filter.EncodingFilter</filter-class><br />    </filter><br />    <filter-mapping><br />        <filter-name>EncodingFilter</filter-name><br />        <url-pattern>/*</url-pattern><br />    </filter-mapping>

<filter><br />        <filter-name>IllegalCharFilter</filter-name><br />        <filter-class>com.atguigu.filter.IllegalCharFilter</filter-class><br />    </filter><br />    <filter-mapping><br />        <filter-name>IllegalCharFilter</filter-name><br />        <url-pattern>/illegal/*</url-pattern><br />    </filter-mapping>

<servlet><br />        <servlet-name>CommentServlet</servlet-name><br />        <servlet-class>com.atguigu.servlet.CommentServlet</servlet-class><br />    </servlet><br />    <servlet-mapping><br />        <servlet-name>CommentServlet</servlet-name><br />        <url-pattern>/illegal/comment</url-pattern><br />    </servlet-mapping><br /></web-app><br />

非法字符过滤案例V2版本

1. 目标

在第一个版本的基础之上,将固定的非法字符串替换成从illegal.txt文件中读取非法字符串

2. 代码实现

IllegalFilter的代码
package com.atguigu.filter;

import javax.servlet.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

/*
@author chenxin
日期2021-05-18 10:22
/
public class IllegalCharFilter implements Filter {
private List illegalTextList = new ArrayList<>();
@Override
public void destroy() {
}

@Override<br />    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {<br />        //1. 获取客户端提交的评论内容<br />        String content = req.getParameter("content");<br />        if (content != null) {<br />            //3. 判断content中是否包含非法字符<br />            for (String illegalText : illegalTextList) {<br />                if (content.contains(illegalText)) {<br />                    resp.getWriter().write("评论内容中包含非法字符,评论发布失败!!!");<br />                    return;<br />                }<br />            }<br />        }<br />        chain.doFilter(req, resp);<br />    }

@Override<br />    public void init(FilterConfig config) throws ServletException {<br />        //在这里读取illegal.txt文件,就只需要在项目部署的时候读取一次<br />        //将字节输入流进行包装--->InputStreamReader()----->BufferedReader()---->readLine<br />        BufferedReader bufferedReader = null;<br />        try {<br />            bufferedReader = new BufferedReader(new InputStreamReader(IllegalCharFilter.class.getClassLoader().getResourceAsStream("illegal.txt"), "UTF-8"));<br />            String illegalText = null;<br />            while ((illegalText = bufferedReader.readLine()) != null) {<br />                //将读到的那个字符串存储到集合中<br />                illegalTextList.add(illegalText);<br />            }<br />        }catch (Exception e){<br />            e.printStackTrace();<br />        }finally {<br />            try {<br />                bufferedReader.close();<br />            } catch (IOException e) {<br />                e.printStackTrace();<br />            }<br />        }<br />    }<br />}<br />其它的代码和V1版本相同<br />

第十二章 Listener

1. 目标

  • 了解监听器的概念
  • 掌握ServletContextListener的使用

2. 内容讲解

2.1 监听器的简介

2.1.1 监听器的概念

监听器:专门用于对其他对象身上发生的事件或状态改变进行监听和相应处理的对象,当被监视的对象发生情况时,立即采取相应的行动。 Servlet监听器:Servlet规范中定义的一种特殊类,它用于监听Web应用程序中的ServletContext,HttpSession 和HttpServletRequest等域对象的创建与销毁事件,以及监听这些域对象中的属性发生修改的事件。

2.1.2 Servlet监听器的分类(了解)

2.1.2.1 ServletContextListener

作用:监听ServletContext对象的创建与销毁

方法名 作用
contextInitialized(ServletContextEvent sce) ServletContext创建时调用
contextDestroyed(ServletContextEvent sce) ServletContext销毁时调用

ServletContextEvent对象代表从ServletContext对象身上捕获到的事件,通过这个事件对象我们可以获取到ServletContext对象。

2.1.2.2 HttpSessionListener

作用:监听HttpSession对象的创建与销毁

方法名 作用
sessionCreated(HttpSessionEvent hse) HttpSession对象创建时调用
sessionDestroyed(HttpSessionEvent hse) HttpSession对象销毁时调用

HttpSessionEvent对象代表从HttpSession对象身上捕获到的事件,通过这个事件对象我们可以获取到触发事件的HttpSession对象。

2.1.2.3 ServletRequestListener

作用:监听ServletRequest对象的创建与销毁

方法名 作用
requestInitialized(ServletRequestEvent sre) ServletRequest对象创建时调用
requestDestroyed(ServletRequestEvent sre) ServletRequest对象销毁时调用

ServletRequestEvent对象代表从HttpServletRequest对象身上捕获到的事件,通过这个事件对象我们可以获取到触发事件的HttpServletRequest对象。另外还有一个方法可以获取到当前Web应用的ServletContext对象。

2.1.2.4 ServletContextAttributeListener

作用:监听ServletContext中属性的创建、修改和销毁

方法名 作用
attributeAdded(ServletContextAttributeEvent scab) 向ServletContext中添加属性时调用
attributeRemoved(ServletContextAttributeEvent scab) 从ServletContext中移除属性时调用
attributeReplaced(ServletContextAttributeEvent scab) 当ServletContext中的属性被修改时调用

ServletContextAttributeEvent对象代表属性变化事件,它包含的方法如下:

方法名 作用
getName() 获取修改或添加的属性名
getValue() 获取被修改或添加的属性值
getServletContext() 获取ServletContext对象

2.1.2.5 HttpSessionAttributeListener

作用:监听HttpSession中属性的创建、修改和销毁

方法名 作用
attributeAdded(HttpSessionBindingEvent se) 向HttpSession中添加属性时调用
attributeRemoved(HttpSessionBindingEvent se) 从HttpSession中移除属性时调用
attributeReplaced(HttpSessionBindingEvent se) 当HttpSession中的属性被修改时调用

HttpSessionBindingEvent对象代表属性变化事件,它包含的方法如下:

方法名 作用
getName() 获取修改或添加的属性名
getValue() 获取被修改或添加的属性值
getSession() 获取触发事件的HttpSession对象

2.1.2.6 ServletRequestAttributeListener

作用:监听ServletRequest中属性的创建、修改和销毁

方法名 作用
attributeAdded(ServletRequestAttributeEvent srae) 向ServletRequest中添加属性时调用
attributeRemoved(ServletRequestAttributeEvent srae) 从ServletRequest中移除属性时调用
attributeReplaced(ServletRequestAttributeEvent srae) 当ServletRequest中的属性被修改时调用

ServletRequestAttributeEvent对象代表属性变化事件,它包含的方法如下:

方法名 作用
getName() 获取修改或添加的属性名
getValue() 获取被修改或添加的属性值
getServletRequest () 获取触发事件的ServletRequest对象

2.1.2.7 HttpSessionBindingListener

作用:监听某个对象在Session域中的创建与移除

方法名 作用
valueBound(HttpSessionBindingEvent event) 该类的实例被放到Session域中时调用
valueUnbound(HttpSessionBindingEvent event) 该类的实例从Session中移除时调用

HttpSessionBindingEvent对象代表属性变化事件,它包含的方法如下:

方法名 作用
getName() 获取当前事件涉及的属性名
getValue() 获取当前事件涉及的属性值
getSession() 获取触发事件的HttpSession对象

2.2.3.2 注册监听器



com.atguigu.listener.MyContextListener

第十三章 Ajax&Axios

第一章 Ajax

1. 学习目标

  • 了解服务器渲染和Ajax渲染的区别
  • 了解同步和异步的区别

2. 内容讲解

2.1 服务器端渲染

JavaWEB葵花宝典 - 图117
images

2.2 Ajax渲染(局部更新)

JavaWEB葵花宝典 - 图118
images

2.3 同步与异步

Ajax本身就是Asynchronous JavaScript And XML的缩写,直译为:异步的JavaScript和XML。在实际应用中Ajax指的是:不刷新浏览器窗口,不做页面跳转,局部更新页面内容的技术。
『同步』和『异步』是一对相对的概念,那么什么是同步,什么是异步呢?

2.3.1 同步

多个操作按顺序执行,前面的操作没有完成,后面的操作就必须等待。所以同步操作通常是串行的。
JavaWEB葵花宝典 - 图119

2.3.2 异步

多个操作相继开始并发执行,即使开始的先后顺序不同,但是由于它们各自是在自己独立的进程或线程中完成,所以互不干扰,谁也不用等谁。
JavaWEB葵花宝典 - 图120

第二章 Axios

1. 学习目标

  • 了解Axios
  • 掌握Axios发送异步请求
  • 掌握Axios携带json类型的请求参数
  • 掌握服务器端返回json数据

2. 内容讲解

2.1 Axios简介

使用原生的JavaScript程序执行Ajax极其繁琐,所以一定要使用框架来完成。而Axios就是目前最流行的前端Ajax框架。
Axios官网:http://www.axios-js.com/
JavaWEB葵花宝典 - 图121

使用Axios和使用Vue一样,导入对应的*.js文件即可。官方提供的script标签引入方式为:

我们可以把这个axios.min.js文件下载下来保存到本地来使用。

2.2 Axios基本用法

2.2.1 在前端页面引入开发环境



2.2.2 发送普通请求参数

2.2.2.1 前端代码

HTML标签:




Vue+axios代码:
var vue = new Vue({
“el”:”#app”,
“data”:{
“message”:””
},
“methods”:{
commonParam(){
//使用axios发送异步请求
axios({
“method”:”post”,
“url”:”demo01”,
“params”:{
“userName”:”tom”,
“userPwd”:”123456”
}
}).then(response => {
//then里面是处理请求成功的响应数据
//response就是服务器端的响应数据,是json类型的
//response里面的data就是响应体的数据
this.message = response.data
})
}
}
})

效果:所有请求参数都被放到URL地址后面了,哪怕我们现在用的是POST请求方式。

2.2.2.2 后端代码

package com.atguigu.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/*
@author chenxin
日期2021-05-21 09:15
/
public class ServletDemo01 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}

@Override<br />    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {<br />        request.setCharacterEncoding("UTF-8");<br />        response.setContentType("text/html;charset=UTF-8");<br />        //1. 接收请求参数userName和userPwd<br />        String userName = request.getParameter("userName");<br />        String userPwd = request.getParameter("userPwd");<br />        System.out.println(userName + ":" + userPwd);

    //模拟出现异常<br />        //int num = 10/0;

    //2. 向浏览器响应数据<br />        response.getWriter().write("hello world!!!");<br />    }<br />}<br />

2.2.3 axios程序接收到的响应对象结构
属性名 作用
config 调用axios(config对象)方法时传入的JSON对象
data 服务器端返回的响应体数据
headers 响应消息头
request 原生JavaScript执行Ajax操作时使用的XMLHttpRequest
status 响应状态码
statusText 响应状态码的说明文本

2.2.4 服务器端处理请求失败后

catch(error => { // catch()服务器端处理请求出错后,会调用

console.log(error);         // error就是出错时服务器端返回的响应数据<br />    console.log(error.response);        // 在服务器端处理请求失败后,获取axios封装的JSON格式的响应数据对象<br />    console.log(error.response.status); // 在服务器端处理请求失败后,获取响应状态码<br />    console.log(error.response.statusText); // 在服务器端处理请求失败后,获取响应状态说明文本<br />    console.log(error.response.data);   // 在服务器端处理请求失败后,获取响应体数据

});
在给catch()函数传入的回调函数中,error对象封装了服务器端处理请求失败后相应的错误信息。其中,axios封装的响应数据对象,是error对象的response属性。response属性对象的结构如下图所示:
JavaWEB葵花宝典 - 图122

可以看到,response对象的结构还是和then()函数传入的回调函数中的response是一样的:
回调函数:开发人员声明,但是调用时交给系统来调用。像单击响应函数、then()、catch()里面传入的都是回调函数。回调函数是相对于普通函数来说的,普通函数就是开发人员自己声明,自己调用:
function sum(a, b) {
return a+b;
}

var result = sum(3, 2);
console.log(“result=”+result);

2.3 服务器端返回JSON数据

2.3.1 前端代码

sendJsonBody(){
axios({
“method”:”post”,
“url”:”demo03”
}).then(response => {
console.log(response.data.nickname)
})
}

2.3.2 后端代码

2.3.2.1 加入Gson包

仍然需要Gson支持,不用多说
JavaWEB葵花宝典 - 图123

2.3.2.2 Servlet代码

package com.atguigu.servlet;

import com.atguigu.user.User;
import com.atguigu.utils.JsonUtils;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/*
@author chenxin
日期2021-05-21 10:06
/
public class ServletDemo03 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}

@Override<br />    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {<br />        request.setCharacterEncoding("UTF-8");<br />        response.setContentType("text/html;charset=UTF-8");<br />        //1. 创建user对象设置数据<br />        User user = new User(1,"aobama","123456","圣枪游侠");<br />        //2. 创建Gson对象用于将user对象转成json字符串<br />        Gson gson = new Gson();

    //3. 将user对象转成json字符串<br />        String jsonStr = gson.toJson(user);<br />        response.getWriter().write(jsonStr);<br />    }<br />}